LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/gssapi/krb5 - cfx.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 594 975 60.9 %
Date: 2024-01-11 09:59:51 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2003, PADL Software Pty Ltd.
       3             :  * All rights reserved.
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions
       7             :  * are met:
       8             :  *
       9             :  * 1. Redistributions of source code must retain the above copyright
      10             :  *    notice, this list of conditions and the following disclaimer.
      11             :  *
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  *
      16             :  * 3. Neither the name of PADL Software nor the names of its contributors
      17             :  *    may be used to endorse or promote products derived from this software
      18             :  *    without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
      21             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      22             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      23             :  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
      24             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      25             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      26             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      27             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      28             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      29             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      30             :  * SUCH DAMAGE.
      31             :  */
      32             : 
      33             : #include "gsskrb5_locl.h"
      34             : 
      35             : /*
      36             :  * Implementation of RFC 4121
      37             :  */
      38             : 
      39             : #define CFXSentByAcceptor       (1 << 0)
      40             : #define CFXSealed               (1 << 1)
      41             : #define CFXAcceptorSubkey       (1 << 2)
      42             : 
      43             : krb5_error_code
      44      676413 : _gsskrb5cfx_wrap_length_cfx(krb5_context context,
      45             :                             krb5_crypto crypto,
      46             :                             int conf_req_flag,
      47             :                             int dce_style,
      48             :                             size_t input_length,
      49             :                             size_t *output_length,
      50             :                             size_t *cksumsize,
      51             :                             uint16_t *padlength)
      52             : {
      53         930 :     krb5_error_code ret;
      54         930 :     krb5_cksumtype type;
      55             : 
      56             :     /* 16-byte header is always first */
      57      676413 :     *output_length = sizeof(gss_cfx_wrap_token_desc);
      58      676413 :     *padlength = 0;
      59             : 
      60      676413 :     ret = krb5_crypto_get_checksum_type(context, crypto, &type);
      61      676413 :     if (ret)
      62           0 :         return ret;
      63             : 
      64      676413 :     ret = krb5_checksumsize(context, type, cksumsize);
      65      676413 :     if (ret)
      66           0 :         return ret;
      67             : 
      68      676413 :     if (conf_req_flag) {
      69         930 :         size_t padsize;
      70             : 
      71             :         /* Header is concatenated with data before encryption */
      72      675759 :         input_length += sizeof(gss_cfx_wrap_token_desc);
      73             : 
      74      675759 :         if (dce_style) {
      75           0 :                 ret = krb5_crypto_getblocksize(context, crypto, &padsize);
      76             :         } else {
      77      675759 :                 ret = krb5_crypto_getpadsize(context, crypto, &padsize);
      78             :         }
      79      675759 :         if (ret) {
      80           0 :             return ret;
      81             :         }
      82      675759 :         if (padsize > 1) {
      83             :             /* XXX check this */
      84           0 :             *padlength = padsize - (input_length % padsize);
      85             : 
      86             :             /* We add the pad ourselves (noted here for completeness only) */
      87           0 :             input_length += *padlength;
      88             :         }
      89             : 
      90      675759 :         *output_length += krb5_get_wrapped_length(context,
      91             :                                                   crypto, input_length);
      92             :     } else {
      93             :         /* Checksum is concatenated with data */
      94         654 :         *output_length += input_length + *cksumsize;
      95             :     }
      96             : 
      97      676413 :     assert(*output_length > input_length);
      98             : 
      99      675483 :     return 0;
     100             : }
     101             : 
     102             : OM_uint32
     103       23807 : _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
     104             :                       const gsskrb5_ctx ctx,
     105             :                       krb5_context context,
     106             :                       int conf_req_flag,
     107             :                       gss_qop_t qop_req,
     108             :                       OM_uint32 req_output_size,
     109             :                       OM_uint32 *max_input_size)
     110             : {
     111         244 :     krb5_error_code ret;
     112             : 
     113       23807 :     *max_input_size = 0;
     114             : 
     115             :     /* 16-byte header is always first */
     116       23807 :     if (req_output_size < 16)
     117           0 :         return 0;
     118       23807 :     req_output_size -= 16;
     119             : 
     120       23807 :     if (conf_req_flag) {
     121         244 :         size_t wrapped_size, sz;
     122             : 
     123       23645 :         wrapped_size = req_output_size + 1;
     124        7076 :         do {
     125      685705 :             wrapped_size--;
     126      685705 :             sz = krb5_get_wrapped_length(context,
     127             :                                          ctx->crypto, wrapped_size);
     128      685705 :         } while (wrapped_size && sz > req_output_size);
     129       23645 :         if (wrapped_size == 0)
     130           0 :             return 0;
     131             : 
     132             :         /* inner header */
     133       23645 :         if (wrapped_size < 16)
     134           0 :             return 0;
     135             : 
     136       23645 :         wrapped_size -= 16;
     137             : 
     138       23645 :         *max_input_size = wrapped_size;
     139             :     } else {
     140           0 :         krb5_cksumtype type;
     141           0 :         size_t cksumsize;
     142             : 
     143         162 :         ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);
     144         162 :         if (ret)
     145           0 :             return ret;
     146             : 
     147         162 :         ret = krb5_checksumsize(context, type, &cksumsize);
     148         162 :         if (ret)
     149           0 :             return ret;
     150             : 
     151         162 :         if (req_output_size < cksumsize)
     152           0 :             return 0;
     153             : 
     154             :         /* Checksum is concatenated with data */
     155         162 :         *max_input_size = req_output_size - cksumsize;
     156             :     }
     157             : 
     158       23563 :     return 0;
     159             : }
     160             : 
     161             : /*
     162             :  * Rotate "rrc" bytes to the front or back
     163             :  */
     164             : 
     165             : static krb5_error_code
     166     1352672 : rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
     167             : {
     168        1860 :     u_char *tmp, buf[256];
     169        1860 :     size_t left;
     170             : 
     171     1352672 :     if (len == 0)
     172           0 :         return 0;
     173             : 
     174     1352672 :     rrc %= len;
     175             : 
     176     1352672 :     if (rrc == 0)
     177           0 :         return 0;
     178             : 
     179     1352672 :     left = len - rrc;
     180             : 
     181     1352672 :     if (rrc <= sizeof(buf)) {
     182     1350812 :         tmp = buf;
     183             :     } else {
     184           0 :         tmp = malloc(rrc);
     185           0 :         if (tmp == NULL)
     186           0 :             return ENOMEM;
     187             :     }
     188             : 
     189     1352672 :     if (unrotate) {
     190      676259 :         memcpy(tmp, data, rrc);
     191      676259 :         memmove(data, (u_char *)data + rrc, left);
     192      676259 :         memcpy((u_char *)data + left, tmp, rrc);
     193             :     } else {
     194      676413 :         memcpy(tmp, (u_char *)data + left, rrc);
     195      676413 :         memmove((u_char *)data + rrc, data, left);
     196      676413 :         memcpy(data, tmp, rrc);
     197             :     }
     198             : 
     199     1352672 :     if (rrc > sizeof(buf))
     200           0 :         free(tmp);
     201             : 
     202     1350812 :     return 0;
     203             : }
     204             : 
     205             : gss_iov_buffer_desc *
     206     4921593 : _gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
     207             : {
     208        7875 :     int i;
     209     4921593 :     gss_iov_buffer_t iovp = GSS_C_NO_IOV_BUFFER;
     210             : 
     211     4921593 :     if (iov == GSS_C_NO_IOV_BUFFER)
     212           0 :         return GSS_C_NO_IOV_BUFFER;
     213             : 
     214             :     /*
     215             :      * This function is used to find header, padding or trailer buffers
     216             :      * which are singletons; return NULL if multiple instances are found.
     217             :      */
     218    24607965 :     for (i = 0; i < iov_count; i++) {
     219    19686372 :         if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) {
     220     1640531 :             if (iovp == GSS_C_NO_IOV_BUFFER)
     221     1637906 :                 iovp = &iov[i];
     222             :             else
     223           0 :                 return GSS_C_NO_IOV_BUFFER;
     224             :         }
     225             :     }
     226             : 
     227             :     /*
     228             :      * For compatibility with SSPI, an empty padding buffer is treated
     229             :      * equivalent to an absent padding buffer (unless the caller is
     230             :      * requesting that a padding buffer be allocated).
     231             :      */
     232     4921593 :     if (iovp &&
     233     1640531 :         iovp->buffer.length == 0 &&
     234           0 :         type == GSS_IOV_BUFFER_TYPE_PADDING &&
     235           0 :         (GSS_IOV_BUFFER_FLAGS(iovp->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) == 0)
     236           0 :         iovp = NULL;
     237             : 
     238     4913718 :     return iovp;
     239             : }
     240             : 
     241             : OM_uint32
     242           0 : _gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size)
     243             : {
     244           0 :     if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
     245           0 :         if (buffer->buffer.length == size)
     246           0 :             return GSS_S_COMPLETE;
     247           0 :         free(buffer->buffer.value);
     248             :     }
     249             : 
     250           0 :     buffer->buffer.value = malloc(size);
     251           0 :     buffer->buffer.length = size;
     252           0 :     if (buffer->buffer.value == NULL) {
     253           0 :         *minor_status = ENOMEM;
     254           0 :         return GSS_S_FAILURE;
     255             :     }
     256           0 :     buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
     257             : 
     258           0 :     return GSS_S_COMPLETE;
     259             : }
     260             : 
     261             : 
     262             : OM_uint32
     263     1656408 : _gk_verify_buffers(OM_uint32 *minor_status,
     264             :                    const gsskrb5_ctx ctx,
     265             :                    const gss_iov_buffer_desc *header,
     266             :                    const gss_iov_buffer_desc *padding,
     267             :                    const gss_iov_buffer_desc *trailer,
     268             :                    int block_cipher)
     269             : {
     270     1656408 :     if (header == NULL) {
     271           0 :         *minor_status = EINVAL;
     272           0 :         return GSS_S_FAILURE;
     273             :     }
     274             : 
     275     1656408 :     if (IS_DCE_STYLE(ctx)) {
     276             :         /*
     277             :          * In DCE style mode we reject having a padding or trailer buffer
     278             :          */
     279     1656408 :         if (padding || trailer) {
     280           0 :             *minor_status = EINVAL;
     281           0 :             return GSS_S_FAILURE;
     282             :         }
     283             :     } else {
     284             :         /*
     285             :          * In non-DCE style mode we require having a padding buffer for
     286             :          * encryption types that do not behave as stream ciphers. This
     287             :          * check is superfluous for now, as only RC4 and RFC4121 enctypes
     288             :          * are presently implemented for the IOV APIs; be defensive.
     289             :          */
     290           0 :         if (block_cipher && padding == NULL) {
     291           0 :             *minor_status = EINVAL;
     292           0 :             return GSS_S_FAILURE;
     293             :         }
     294             :     }
     295             : 
     296     1656408 :     *minor_status = 0;
     297     1656408 :     return GSS_S_COMPLETE;
     298             : }
     299             : 
     300             : OM_uint32
     301     1181389 : _gssapi_wrap_cfx_iov(OM_uint32 *minor_status,
     302             :                      gsskrb5_ctx ctx,
     303             :                      krb5_context context,
     304             :                      int conf_req_flag,
     305             :                      int *conf_state,
     306             :                      gss_iov_buffer_desc *iov,
     307             :                      int iov_count)
     308             : {
     309        1313 :     OM_uint32 major_status, junk;
     310        1313 :     gss_iov_buffer_desc *header, *trailer, *padding;
     311        1313 :     size_t gsshsize, k5hsize;
     312        1313 :     size_t gsstsize, k5tsize;
     313     1181389 :     size_t rrc = 0, ec = 0;
     314        1313 :     int i;
     315        1313 :     gss_cfx_wrap_token token;
     316        1313 :     krb5_error_code ret;
     317        1313 :     int32_t seq_number;
     318        1313 :     unsigned usage;
     319     1181389 :     krb5_crypto_iov *data = NULL;
     320             : 
     321     1181389 :     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
     322     1181389 :     if (header == NULL) {
     323           0 :         *minor_status = EINVAL;
     324           0 :         return GSS_S_FAILURE;
     325             :     }
     326             : 
     327     1181389 :     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
     328     1181389 :     if (padding != NULL) {
     329           0 :         padding->buffer.length = 0;
     330             :     }
     331             : 
     332     1181389 :     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
     333             : 
     334     1181389 :     major_status = _gk_verify_buffers(minor_status, ctx, header,
     335             :                                       padding, trailer, FALSE);
     336     1181389 :     if (major_status != GSS_S_COMPLETE) {
     337           0 :             return major_status;
     338             :     }
     339             : 
     340     1181389 :     if (conf_req_flag) {
     341     1181389 :         size_t k5psize = 0;
     342     1181389 :         size_t k5pbase = 0;
     343     1181389 :         size_t k5bsize = 0;
     344     1181389 :         size_t size = 0;
     345             : 
     346     5906945 :         for (i = 0; i < iov_count; i++) {
     347     4725556 :             switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
     348     1181389 :             case GSS_IOV_BUFFER_TYPE_DATA:
     349     1181389 :                 size += iov[i].buffer.length;
     350     1181389 :                 break;
     351     3540228 :             default:
     352     3540228 :                 break;
     353             :             }
     354             :         }
     355             : 
     356     1181389 :         size += sizeof(gss_cfx_wrap_token_desc);
     357             : 
     358     1181389 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
     359             :                                            KRB5_CRYPTO_TYPE_HEADER,
     360             :                                            &k5hsize);
     361     1181389 :         if (*minor_status)
     362           0 :             return GSS_S_FAILURE;
     363             : 
     364     1181389 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
     365             :                                            KRB5_CRYPTO_TYPE_TRAILER,
     366             :                                            &k5tsize);
     367     1181389 :         if (*minor_status)
     368           0 :             return GSS_S_FAILURE;
     369             : 
     370     1181389 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
     371             :                                            KRB5_CRYPTO_TYPE_PADDING,
     372             :                                            &k5pbase);
     373     1181389 :         if (*minor_status)
     374           0 :             return GSS_S_FAILURE;
     375             : 
     376     1181389 :         if (k5pbase > 1) {
     377           0 :             k5psize = k5pbase - (size % k5pbase);
     378             :         } else {
     379     1180076 :             k5psize = 0;
     380             :         }
     381             : 
     382     1181389 :         if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
     383     1181389 :             *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
     384             :                                                      &k5bsize);
     385     1181389 :             if (*minor_status)
     386           0 :                 return GSS_S_FAILURE;
     387     1181389 :             ec = k5bsize;
     388             :         } else {
     389           0 :             ec = k5psize;
     390             :         }
     391             : 
     392     1181389 :         gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
     393     1181389 :         gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
     394             :     } else {
     395           0 :         if (IS_DCE_STYLE(ctx)) {
     396           0 :             *minor_status = EINVAL;
     397           0 :             return GSS_S_FAILURE;
     398             :         }
     399             : 
     400           0 :         k5hsize = 0;
     401           0 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
     402             :                                            KRB5_CRYPTO_TYPE_CHECKSUM,
     403             :                                            &k5tsize);
     404           0 :         if (*minor_status)
     405           0 :             return GSS_S_FAILURE;
     406             : 
     407           0 :         gsshsize = sizeof(gss_cfx_wrap_token_desc);
     408           0 :         gsstsize = k5tsize;
     409             :     }
     410             : 
     411             :     /*
     412             :      *
     413             :      */
     414             : 
     415     1181389 :     if (trailer == NULL) {
     416     1181389 :         rrc = gsstsize;
     417     1181389 :         if (IS_DCE_STYLE(ctx))
     418     1181389 :             rrc -= ec;
     419     1181389 :         gsshsize += gsstsize;
     420           0 :     } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
     421           0 :         major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize);
     422           0 :         if (major_status)
     423           0 :             goto failure;
     424           0 :     } else if (trailer->buffer.length < gsstsize) {
     425           0 :         *minor_status = KRB5_BAD_MSIZE;
     426           0 :         major_status = GSS_S_FAILURE;
     427           0 :         goto failure;
     428             :     } else
     429           0 :         trailer->buffer.length = gsstsize;
     430             : 
     431             :     /*
     432             :      *
     433             :      */
     434             : 
     435     1181389 :     if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
     436           0 :         major_status = _gk_allocate_buffer(minor_status, header, gsshsize);
     437           0 :         if (major_status != GSS_S_COMPLETE)
     438           0 :             goto failure;
     439     1181389 :     } else if (header->buffer.length < gsshsize) {
     440           0 :         *minor_status = KRB5_BAD_MSIZE;
     441           0 :         major_status = GSS_S_FAILURE;
     442           0 :         goto failure;
     443             :     } else
     444     1181389 :         header->buffer.length = gsshsize;
     445             : 
     446     1181389 :     token = (gss_cfx_wrap_token)header->buffer.value;
     447             : 
     448     1181389 :     token->TOK_ID[0] = 0x05;
     449     1181389 :     token->TOK_ID[1] = 0x04;
     450     1181389 :     token->Flags     = 0;
     451     1181389 :     token->Filler    = 0xFF;
     452             : 
     453     1181389 :     if ((ctx->more_flags & LOCAL) == 0)
     454     1151418 :         token->Flags |= CFXSentByAcceptor;
     455             : 
     456     1181389 :     if (ctx->more_flags & ACCEPTOR_SUBKEY)
     457     1181389 :         token->Flags |= CFXAcceptorSubkey;
     458             : 
     459     1181389 :     if (ctx->more_flags & LOCAL)
     460       29305 :         usage = KRB5_KU_USAGE_INITIATOR_SEAL;
     461             :     else
     462     1151418 :         usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
     463             : 
     464     1181389 :     if (conf_req_flag) {
     465             :         /*
     466             :          * In Wrap tokens with confidentiality, the EC field is
     467             :          * used to encode the size (in bytes) of the random filler.
     468             :          */
     469     1181389 :         token->Flags |= CFXSealed;
     470     1181389 :         token->EC[0] = (ec >> 8) & 0xFF;
     471     1181389 :         token->EC[1] = (ec >> 0) & 0xFF;
     472             : 
     473             :     } else {
     474             :         /*
     475             :          * In Wrap tokens without confidentiality, the EC field is
     476             :          * used to encode the size (in bytes) of the trailing
     477             :          * checksum.
     478             :          *
     479             :          * This is not used in the checksum calcuation itself,
     480             :          * because the checksum length could potentially vary
     481             :          * depending on the data length.
     482             :          */
     483           0 :         token->EC[0] = 0;
     484           0 :         token->EC[1] = 0;
     485             :     }
     486             : 
     487             :     /*
     488             :      * In Wrap tokens that provide for confidentiality, the RRC
     489             :      * field in the header contains the hex value 00 00 before
     490             :      * encryption.
     491             :      *
     492             :      * In Wrap tokens that do not provide for confidentiality,
     493             :      * both the EC and RRC fields in the appended checksum
     494             :      * contain the hex value 00 00 for the purpose of calculating
     495             :      * the checksum.
     496             :      */
     497     1181389 :     token->RRC[0] = 0;
     498     1181389 :     token->RRC[1] = 0;
     499             : 
     500        1313 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
     501     1181389 :     krb5_auth_con_getlocalseqnumber(context,
     502             :                                     ctx->auth_context,
     503             :                                     &seq_number);
     504     1181389 :     _gss_mg_encode_be_uint32(0,          &token->SND_SEQ[0]);
     505     1181389 :     _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]);
     506     1181389 :     krb5_auth_con_setlocalseqnumber(context,
     507             :                                     ctx->auth_context,
     508             :                                     ++seq_number);
     509        1313 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     510             : 
     511     1181389 :     data = calloc(iov_count + 3, sizeof(data[0]));
     512     1181389 :     if (data == NULL) {
     513           0 :         *minor_status = ENOMEM;
     514           0 :         major_status = GSS_S_FAILURE;
     515           0 :         goto failure;
     516             :     }
     517             : 
     518     1181389 :     if (conf_req_flag) {
     519             :         /*
     520             :           plain packet:
     521             : 
     522             :           {"header" | encrypt(plaintext-data | ec-padding | E"header")}
     523             : 
     524             :           Expanded, this is with with RRC = 0:
     525             : 
     526             :           {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }
     527             : 
     528             :           In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)
     529             : 
     530             :           {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data  }
     531             :          */
     532             : 
     533     1181389 :         i = 0;
     534     1181389 :         data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
     535     1181389 :         data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
     536     1181389 :         data[i].data.length = k5hsize;
     537             : 
     538     5906945 :         for (i = 1; i < iov_count + 1; i++) {
     539     4725556 :             switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
     540     1181389 :             case GSS_IOV_BUFFER_TYPE_DATA:
     541     1181389 :                 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     542     1181389 :                 break;
     543     2337540 :             case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
     544     2337540 :                 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
     545     2337540 :                 break;
     546     1206627 :             default:
     547     1206627 :                 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
     548     1206627 :                 break;
     549             :             }
     550     4725556 :             data[i].data.length = iov[i - 1].buffer.length;
     551     4725556 :             data[i].data.data = iov[i - 1].buffer.value;
     552             :         }
     553             : 
     554             :         /*
     555             :          * Any necessary padding is added here to ensure that the
     556             :          * encrypted token header is always at the end of the
     557             :          * ciphertext.
     558             :          */
     559             : 
     560             :         /* encrypted CFX header in trailer (or after the header if in
     561             :            DCE mode). Copy in header into E"header"
     562             :         */
     563     1181389 :         data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     564     1181389 :         if (trailer)
     565           0 :             data[i].data.data = trailer->buffer.value;
     566             :         else
     567     1181389 :             data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
     568             : 
     569     1181389 :         data[i].data.length = ec + sizeof(*token);
     570     1181389 :         memset(data[i].data.data, 0xFF, ec);
     571     1181389 :         memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
     572     1181389 :         i++;
     573             : 
     574             :         /* Kerberos trailer comes after the gss trailer */
     575     1181389 :         data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
     576     1181389 :         data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
     577     1181389 :         data[i].data.length = k5tsize;
     578     1181389 :         i++;
     579             : 
     580     1181389 :         ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
     581     1181389 :         if (ret != 0) {
     582           0 :             *minor_status = ret;
     583           0 :             major_status = GSS_S_FAILURE;
     584           0 :             goto failure;
     585             :         }
     586             : 
     587     1181389 :         if (rrc) {
     588     1181389 :             token->RRC[0] = (rrc >> 8) & 0xFF;
     589     1181389 :             token->RRC[1] = (rrc >> 0) & 0xFF;
     590             :         }
     591             : 
     592             :     } else {
     593             :         /*
     594             :           plain packet:
     595             : 
     596             :           {data | "header" | gss-trailer (krb5 checksum)
     597             : 
     598             :           don't do RRC != 0
     599             : 
     600             :          */
     601             : 
     602           0 :         for (i = 0; i < iov_count; i++) {
     603           0 :             switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
     604           0 :             case GSS_IOV_BUFFER_TYPE_DATA:
     605           0 :                 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     606           0 :                 break;
     607           0 :             case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
     608           0 :                 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
     609           0 :                 break;
     610           0 :             default:
     611           0 :                 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
     612           0 :                 break;
     613             :             }
     614           0 :             data[i].data.length = iov[i].buffer.length;
     615           0 :             data[i].data.data = iov[i].buffer.value;
     616             :         }
     617             : 
     618           0 :         data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     619           0 :         data[i].data.data = header->buffer.value;
     620           0 :         data[i].data.length = sizeof(gss_cfx_wrap_token_desc);
     621           0 :         i++;
     622             : 
     623           0 :         data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
     624           0 :         if (trailer) {
     625           0 :                 data[i].data.data = trailer->buffer.value;
     626             :         } else {
     627           0 :                 data[i].data.data = (uint8_t *)header->buffer.value +
     628             :                                      sizeof(gss_cfx_wrap_token_desc);
     629             :         }
     630           0 :         data[i].data.length = k5tsize;
     631           0 :         i++;
     632             : 
     633           0 :         ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
     634           0 :         if (ret) {
     635           0 :             *minor_status = ret;
     636           0 :             major_status = GSS_S_FAILURE;
     637           0 :             goto failure;
     638             :         }
     639             : 
     640           0 :         if (rrc) {
     641           0 :             token->RRC[0] = (rrc >> 8) & 0xFF;
     642           0 :             token->RRC[1] = (rrc >> 0) & 0xFF;
     643             :         }
     644             : 
     645           0 :         token->EC[0] =  (k5tsize >> 8) & 0xFF;
     646           0 :         token->EC[1] =  (k5tsize >> 0) & 0xFF;
     647             :     }
     648             : 
     649     1181389 :     if (conf_state != NULL)
     650     1181389 :         *conf_state = conf_req_flag;
     651             : 
     652     1181389 :     free(data);
     653             : 
     654     1181389 :     *minor_status = 0;
     655     1181389 :     return GSS_S_COMPLETE;
     656             : 
     657           0 :  failure:
     658           0 :     if (data)
     659           0 :         free(data);
     660             : 
     661           0 :     gss_release_iov_buffer(&junk, iov, iov_count);
     662             : 
     663           0 :     return major_status;
     664             : }
     665             : 
     666             : /* This is slowpath */
     667             : static OM_uint32
     668           0 : unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count)
     669             : {
     670           0 :     uint8_t *p, *q;
     671           0 :     size_t len = 0, skip;
     672           0 :     int i;
     673             : 
     674           0 :     for (i = 0; i < iov_count; i++)
     675           0 :         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
     676           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
     677           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
     678           0 :             len += iov[i].buffer.length;
     679             : 
     680           0 :     p = malloc(len);
     681           0 :     if (p == NULL) {
     682           0 :         *minor_status = ENOMEM;
     683           0 :         return GSS_S_FAILURE;
     684             :     }
     685           0 :     q = p;
     686             : 
     687             :     /* copy up */
     688             : 
     689           0 :     for (i = 0; i < iov_count; i++) {
     690           0 :         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
     691           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
     692           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
     693             :         {
     694           0 :             memcpy(q, iov[i].buffer.value, iov[i].buffer.length);
     695           0 :             q += iov[i].buffer.length;
     696             :         }
     697             :     }
     698           0 :     assert((size_t)(q - p) == len);
     699             : 
     700             :     /* unrotate first part */
     701           0 :     q = p + rrc;
     702           0 :     skip = rrc;
     703           0 :     for (i = 0; i < iov_count; i++) {
     704           0 :         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
     705           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
     706           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
     707             :         {
     708           0 :             if (iov[i].buffer.length <= skip) {
     709           0 :                 skip -= iov[i].buffer.length;
     710             :             } else {
     711             :                 /* copy back to original buffer */
     712           0 :                 memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip);
     713           0 :                 q += iov[i].buffer.length - skip;
     714           0 :                 skip = 0;
     715             :             }
     716             :         }
     717             :     }
     718             :     /* copy trailer */
     719           0 :     q = p;
     720           0 :     skip = rrc;
     721           0 :     for (i = 0; i < iov_count; i++) {
     722           0 :         if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
     723           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
     724           0 :             GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
     725             :         {
     726           0 :             memcpy(iov[i].buffer.value, q, min(iov[i].buffer.length, skip));
     727           0 :             if (iov[i].buffer.length > skip)
     728           0 :                 break;
     729           0 :             skip -= iov[i].buffer.length;
     730           0 :             q += iov[i].buffer.length;
     731             :         }
     732             :     }
     733           0 :     free(p);
     734           0 :     return GSS_S_COMPLETE;
     735             : }
     736             : 
     737             : 
     738             : OM_uint32
     739      429508 : _gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,
     740             :                        gsskrb5_ctx ctx,
     741             :                        krb5_context context,
     742             :                        int *conf_state,
     743             :                        gss_qop_t *qop_state,
     744             :                        gss_iov_buffer_desc *iov,
     745             :                        int iov_count)
     746             : {
     747        1312 :     OM_uint32 seq_number_lo, seq_number_hi, major_status, junk;
     748        1312 :     gss_iov_buffer_desc *header, *trailer, *padding;
     749        1312 :     gss_cfx_wrap_token token, ttoken;
     750        1312 :     u_char token_flags;
     751        1312 :     krb5_error_code ret;
     752        1312 :     unsigned usage;
     753        1312 :     uint16_t ec, rrc;
     754      429508 :     krb5_crypto_iov *data = NULL;
     755        1312 :     int i, j;
     756             : 
     757      429508 :     *minor_status = 0;
     758             : 
     759      429508 :     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
     760      429508 :     if (header == NULL) {
     761           0 :         *minor_status = EINVAL;
     762           0 :         return GSS_S_FAILURE;
     763             :     }
     764             : 
     765      429508 :     if (header->buffer.length < sizeof(*token)) /* we check exact below */
     766           0 :         return GSS_S_DEFECTIVE_TOKEN;
     767             : 
     768      429508 :     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
     769      429508 :     if (padding != NULL && padding->buffer.length != 0) {
     770           0 :         *minor_status = EINVAL;
     771           0 :         return GSS_S_FAILURE;
     772             :     }
     773             : 
     774      429508 :     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
     775             : 
     776      429508 :     major_status = _gk_verify_buffers(minor_status, ctx, header,
     777             :                                       padding, trailer, FALSE);
     778      429508 :     if (major_status != GSS_S_COMPLETE) {
     779           0 :             return major_status;
     780             :     }
     781             : 
     782      429508 :     token = (gss_cfx_wrap_token)header->buffer.value;
     783             : 
     784      429508 :     if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
     785           0 :         return GSS_S_DEFECTIVE_TOKEN;
     786             : 
     787             :     /* Ignore unknown flags */
     788      429508 :     token_flags = token->Flags &
     789             :         (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
     790             : 
     791      429508 :     if (token_flags & CFXSentByAcceptor) {
     792      270391 :         if ((ctx->more_flags & LOCAL) == 0)
     793           0 :             return GSS_S_DEFECTIVE_TOKEN;
     794             :     }
     795             : 
     796      429508 :     if (ctx->more_flags & ACCEPTOR_SUBKEY) {
     797      429508 :         if ((token_flags & CFXAcceptorSubkey) == 0)
     798           0 :             return GSS_S_DEFECTIVE_TOKEN;
     799             :     } else {
     800           0 :         if (token_flags & CFXAcceptorSubkey)
     801           0 :             return GSS_S_DEFECTIVE_TOKEN;
     802             :     }
     803             : 
     804      429508 :     if (token->Filler != 0xFF)
     805           0 :         return GSS_S_DEFECTIVE_TOKEN;
     806             : 
     807      429508 :     if (conf_state != NULL)
     808      429508 :         *conf_state = (token_flags & CFXSealed) ? 1 : 0;
     809             : 
     810      429508 :     ec  = (token->EC[0]  << 8) | token->EC[1];
     811      429508 :     rrc = (token->RRC[0] << 8) | token->RRC[1];
     812             : 
     813             :     /*
     814             :      * Check sequence number
     815             :      */
     816      429508 :     _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi);
     817      429508 :     _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo);
     818      429508 :     if (seq_number_hi) {
     819             :         /* no support for 64-bit sequence numbers */
     820           0 :         *minor_status = ERANGE;
     821           0 :         return GSS_S_UNSEQ_TOKEN;
     822             :     }
     823             : 
     824        1312 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
     825      429508 :     ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
     826      429508 :     if (ret != 0) {
     827           0 :         *minor_status = 0;
     828           0 :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     829           0 :         return ret;
     830             :     }
     831        1312 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     832             : 
     833             :     /*
     834             :      * Decrypt and/or verify checksum
     835             :      */
     836             : 
     837      429508 :     if (ctx->more_flags & LOCAL) {
     838      269744 :         usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
     839             :     } else {
     840      159117 :         usage = KRB5_KU_USAGE_INITIATOR_SEAL;
     841             :     }
     842             : 
     843      429508 :     data = calloc(iov_count + 3, sizeof(data[0]));
     844      429508 :     if (data == NULL) {
     845           0 :         *minor_status = ENOMEM;
     846           0 :         major_status = GSS_S_FAILURE;
     847           0 :         goto failure;
     848             :     }
     849             : 
     850      429508 :     if (token_flags & CFXSealed) {
     851        1312 :         size_t k5tsize, k5hsize;
     852             : 
     853      429508 :         krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
     854      429508 :         krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize);
     855             : 
     856             :         /* Rotate by RRC; bogus to do this in-place XXX */
     857             :         /* Check RRC */
     858             : 
     859      429508 :         if (trailer == NULL) {
     860      429508 :             size_t gsstsize = k5tsize + sizeof(*token);
     861      429508 :             size_t gsshsize = k5hsize + sizeof(*token);
     862             : 
     863      429508 :             if (rrc != gsstsize) {
     864           0 :                 major_status = GSS_S_DEFECTIVE_TOKEN;
     865           0 :                 goto failure;
     866             :             }
     867             : 
     868      429508 :             if (IS_DCE_STYLE(ctx))
     869      429508 :                 gsstsize += ec;
     870             : 
     871      429508 :             gsshsize += gsstsize;
     872             : 
     873      429508 :             if (header->buffer.length != gsshsize) {
     874           0 :                 major_status = GSS_S_DEFECTIVE_TOKEN;
     875           0 :                 goto failure;
     876             :             }
     877           0 :         } else if (trailer->buffer.length != sizeof(*token) + k5tsize) {
     878           0 :             major_status = GSS_S_DEFECTIVE_TOKEN;
     879           0 :             goto failure;
     880           0 :         } else if (header->buffer.length != sizeof(*token) + k5hsize) {
     881           0 :             major_status = GSS_S_DEFECTIVE_TOKEN;
     882           0 :             goto failure;
     883           0 :         } else if (rrc != 0) {
     884             :             /* go though slowpath */
     885           0 :             major_status = unrotate_iov(minor_status, rrc, iov, iov_count);
     886           0 :             if (major_status)
     887           0 :                 goto failure;
     888             :         }
     889             : 
     890      429508 :         i = 0;
     891      429508 :         data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
     892      429508 :         data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
     893      429508 :         data[i].data.length = k5hsize;
     894      429508 :         i++;
     895             : 
     896     2147540 :         for (j = 0; j < iov_count; i++, j++) {
     897     1718032 :             switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
     898      429508 :             case GSS_IOV_BUFFER_TYPE_DATA:
     899      429508 :                 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     900      429508 :                 break;
     901      833764 :             case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
     902      833764 :                 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
     903      833764 :                 break;
     904      454760 :             default:
     905      454760 :                 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
     906      454760 :                 break;
     907             :             }
     908     1718032 :             data[i].data.length = iov[j].buffer.length;
     909     1718032 :             data[i].data.data = iov[j].buffer.value;
     910             :         }
     911             : 
     912             :         /* encrypted CFX header in trailer (or after the header if in
     913             :            DCE mode). Copy in header into E"header"
     914             :         */
     915      429508 :         data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     916      429508 :         if (trailer) {
     917           0 :             data[i].data.data = trailer->buffer.value;
     918             :         } else {
     919      429508 :             data[i].data.data = ((uint8_t *)header->buffer.value) +
     920      429508 :                 header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
     921             :         }
     922             : 
     923      429508 :         data[i].data.length = ec + sizeof(*token);
     924      429508 :         ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
     925      429508 :         i++;
     926             : 
     927             :         /* Kerberos trailer comes after the gss trailer */
     928      429508 :         data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
     929      429508 :         data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
     930      429508 :         data[i].data.length = k5tsize;
     931      429508 :         i++;
     932             : 
     933      429508 :         ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
     934      429508 :         if (ret != 0) {
     935           0 :             *minor_status = ret;
     936           0 :             major_status = GSS_S_FAILURE;
     937           0 :             goto failure;
     938             :         }
     939             : 
     940      429508 :         ttoken->RRC[0] = token->RRC[0];
     941      429508 :         ttoken->RRC[1] = token->RRC[1];
     942             : 
     943             :         /* Check the integrity of the header */
     944      429508 :         if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) {
     945           0 :             major_status = GSS_S_BAD_MIC;
     946           0 :             goto failure;
     947             :         }
     948             :     } else {
     949           0 :         size_t gsstsize = ec;
     950           0 :         size_t gsshsize = sizeof(*token);
     951             : 
     952           0 :         if (trailer == NULL) {
     953             :             /* Check RRC */
     954           0 :             if (rrc != gsstsize) {
     955           0 :                *minor_status = EINVAL;
     956           0 :                major_status = GSS_S_FAILURE;
     957           0 :                goto failure;
     958             :             }
     959             : 
     960           0 :             gsshsize += gsstsize;
     961           0 :         } else if (trailer->buffer.length != gsstsize) {
     962           0 :             major_status = GSS_S_DEFECTIVE_TOKEN;
     963           0 :             goto failure;
     964           0 :         } else if (rrc != 0) {
     965             :             /* Check RRC */
     966           0 :             *minor_status = EINVAL;
     967           0 :             major_status = GSS_S_FAILURE;
     968           0 :             goto failure;
     969             :         }
     970             : 
     971           0 :         if (header->buffer.length != gsshsize) {
     972           0 :             major_status = GSS_S_DEFECTIVE_TOKEN;
     973           0 :             goto failure;
     974             :         }
     975             : 
     976           0 :         for (i = 0; i < iov_count; i++) {
     977           0 :             switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
     978           0 :             case GSS_IOV_BUFFER_TYPE_DATA:
     979           0 :                 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     980           0 :                 break;
     981           0 :             case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
     982           0 :                 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
     983           0 :                 break;
     984           0 :             default:
     985           0 :                 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
     986           0 :                 break;
     987             :             }
     988           0 :             data[i].data.length = iov[i].buffer.length;
     989           0 :             data[i].data.data = iov[i].buffer.value;
     990             :         }
     991             : 
     992           0 :         data[i].flags = KRB5_CRYPTO_TYPE_DATA;
     993           0 :         data[i].data.data = header->buffer.value;
     994           0 :         data[i].data.length = sizeof(*token);
     995           0 :         i++;
     996             : 
     997           0 :         data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
     998           0 :         if (trailer) {
     999           0 :                 data[i].data.data = trailer->buffer.value;
    1000             :         } else {
    1001           0 :                 data[i].data.data = (uint8_t *)header->buffer.value +
    1002             :                                      sizeof(*token);
    1003             :         }
    1004           0 :         data[i].data.length = ec;
    1005           0 :         i++;
    1006             : 
    1007           0 :         token = (gss_cfx_wrap_token)header->buffer.value;
    1008           0 :         token->EC[0]  = 0;
    1009           0 :         token->EC[1]  = 0;
    1010           0 :         token->RRC[0] = 0;
    1011           0 :         token->RRC[1] = 0;
    1012             : 
    1013           0 :         ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
    1014           0 :         if (ret) {
    1015           0 :             *minor_status = ret;
    1016           0 :             major_status = GSS_S_FAILURE;
    1017           0 :             goto failure;
    1018             :         }
    1019             :     }
    1020             : 
    1021      429508 :     if (qop_state != NULL) {
    1022      429508 :         *qop_state = GSS_C_QOP_DEFAULT;
    1023             :     }
    1024             : 
    1025      429508 :     free(data);
    1026             : 
    1027      429508 :     *minor_status = 0;
    1028      429508 :     return GSS_S_COMPLETE;
    1029             : 
    1030           0 :  failure:
    1031           0 :     if (data)
    1032           0 :         free(data);
    1033             : 
    1034           0 :     gss_release_iov_buffer(&junk, iov, iov_count);
    1035             : 
    1036           0 :     return major_status;
    1037             : }
    1038             : 
    1039             : OM_uint32
    1040       15249 : _gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,
    1041             :                             gsskrb5_ctx ctx,
    1042             :                             krb5_context context,
    1043             :                             int conf_req_flag,
    1044             :                             gss_qop_t qop_req,
    1045             :                             int *conf_state,
    1046             :                             gss_iov_buffer_desc *iov,
    1047             :                             int iov_count)
    1048             : {
    1049         184 :     OM_uint32 major_status;
    1050         184 :     size_t size;
    1051         184 :     int i;
    1052       15249 :     gss_iov_buffer_desc *header = NULL;
    1053       15249 :     gss_iov_buffer_desc *padding = NULL;
    1054       15249 :     gss_iov_buffer_desc *trailer = NULL;
    1055       15249 :     size_t gsshsize = 0;
    1056       15249 :     size_t gsstsize = 0;
    1057       15249 :     size_t k5hsize = 0;
    1058       15249 :     size_t k5tsize = 0;
    1059             : 
    1060       15249 :     GSSAPI_KRB5_INIT (&context);
    1061       15249 :     *minor_status = 0;
    1062             : 
    1063       45747 :     for (size = 0, i = 0; i < iov_count; i++) {
    1064       30498 :         switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
    1065           0 :         case GSS_IOV_BUFFER_TYPE_EMPTY:
    1066           0 :             break;
    1067       15249 :         case GSS_IOV_BUFFER_TYPE_DATA:
    1068       15249 :             size += iov[i].buffer.length;
    1069       15249 :             break;
    1070       15249 :         case GSS_IOV_BUFFER_TYPE_HEADER:
    1071       15249 :             if (header != NULL) {
    1072           0 :                 *minor_status = 0;
    1073           0 :                 return GSS_S_FAILURE;
    1074             :             }
    1075       15065 :             header = &iov[i];
    1076       15065 :             break;
    1077           0 :         case GSS_IOV_BUFFER_TYPE_TRAILER:
    1078           0 :             if (trailer != NULL) {
    1079           0 :                 *minor_status = 0;
    1080           0 :                 return GSS_S_FAILURE;
    1081             :             }
    1082           0 :             trailer = &iov[i];
    1083           0 :             break;
    1084           0 :         case GSS_IOV_BUFFER_TYPE_PADDING:
    1085           0 :             if (padding != NULL) {
    1086           0 :                 *minor_status = 0;
    1087           0 :                 return GSS_S_FAILURE;
    1088             :             }
    1089           0 :             padding = &iov[i];
    1090           0 :             break;
    1091           0 :         case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
    1092           0 :             break;
    1093           0 :         default:
    1094           0 :             *minor_status = EINVAL;
    1095           0 :             return GSS_S_FAILURE;
    1096             :         }
    1097             :     }
    1098             : 
    1099       15249 :     major_status = _gk_verify_buffers(minor_status, ctx, header,
    1100             :                                       padding, trailer, FALSE);
    1101       15249 :     if (major_status != GSS_S_COMPLETE) {
    1102           0 :             return major_status;
    1103             :     }
    1104             : 
    1105       15249 :     if (conf_req_flag) {
    1106       15249 :         size_t k5psize = 0;
    1107       15249 :         size_t k5pbase = 0;
    1108       15249 :         size_t k5bsize = 0;
    1109       15249 :         size_t ec = 0;
    1110             : 
    1111       15249 :         size += sizeof(gss_cfx_wrap_token_desc);
    1112             : 
    1113       15249 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
    1114             :                                            KRB5_CRYPTO_TYPE_HEADER,
    1115             :                                            &k5hsize);
    1116       15249 :         if (*minor_status)
    1117           0 :             return GSS_S_FAILURE;
    1118             : 
    1119       15249 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
    1120             :                                            KRB5_CRYPTO_TYPE_TRAILER,
    1121             :                                            &k5tsize);
    1122       15249 :         if (*minor_status)
    1123           0 :             return GSS_S_FAILURE;
    1124             : 
    1125       15249 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
    1126             :                                            KRB5_CRYPTO_TYPE_PADDING,
    1127             :                                            &k5pbase);
    1128       15249 :         if (*minor_status)
    1129           0 :             return GSS_S_FAILURE;
    1130             : 
    1131       15249 :         if (k5pbase > 1) {
    1132           0 :             k5psize = k5pbase - (size % k5pbase);
    1133             :         } else {
    1134       15065 :             k5psize = 0;
    1135             :         }
    1136             : 
    1137       15249 :         if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
    1138       15249 :             *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
    1139             :                                                      &k5bsize);
    1140       15249 :             if (*minor_status)
    1141           0 :                 return GSS_S_FAILURE;
    1142             : 
    1143       15249 :             ec = k5bsize;
    1144             :         } else {
    1145           0 :             ec = k5psize;
    1146             :         }
    1147             : 
    1148       15249 :         gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
    1149       15249 :         gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
    1150             :     } else {
    1151           0 :         *minor_status = krb5_crypto_length(context, ctx->crypto,
    1152             :                                            KRB5_CRYPTO_TYPE_CHECKSUM,
    1153             :                                            &k5tsize);
    1154           0 :         if (*minor_status)
    1155           0 :             return GSS_S_FAILURE;
    1156             : 
    1157           0 :         gsshsize = sizeof(gss_cfx_wrap_token_desc);
    1158           0 :         gsstsize = k5tsize;
    1159             :     }
    1160             : 
    1161       15249 :     if (trailer != NULL) {
    1162           0 :         trailer->buffer.length = gsstsize;
    1163             :     } else {
    1164       15249 :         gsshsize += gsstsize;
    1165             :     }
    1166             : 
    1167       15249 :     header->buffer.length = gsshsize;
    1168             : 
    1169       15249 :     if (padding) {
    1170             :         /* padding is done via EC and is contained in the header or trailer */
    1171           0 :         padding->buffer.length = 0;
    1172             :     }
    1173             : 
    1174       15249 :     if (conf_state) {
    1175       15249 :         *conf_state = conf_req_flag;
    1176             :     }
    1177             : 
    1178       15065 :     return GSS_S_COMPLETE;
    1179             : }
    1180             : 
    1181             : 
    1182             : 
    1183             : 
    1184      676413 : OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
    1185             :                            const gsskrb5_ctx ctx,
    1186             :                            krb5_context context,
    1187             :                            int conf_req_flag,
    1188             :                            const gss_buffer_t input_message_buffer,
    1189             :                            int *conf_state,
    1190             :                            gss_buffer_t output_message_buffer)
    1191             : {
    1192         930 :     gss_cfx_wrap_token token;
    1193         930 :     krb5_error_code ret;
    1194         930 :     unsigned usage;
    1195         930 :     krb5_data cipher;
    1196         930 :     size_t wrapped_len, cksumsize;
    1197      676413 :     uint16_t padlength, rrc = 0;
    1198         930 :     int32_t seq_number;
    1199         930 :     u_char *p;
    1200             : 
    1201      676413 :     ret = _gsskrb5cfx_wrap_length_cfx(context,
    1202             :                                       ctx->crypto, conf_req_flag,
    1203             :                                       IS_DCE_STYLE(ctx),
    1204             :                                       input_message_buffer->length,
    1205             :                                       &wrapped_len, &cksumsize, &padlength);
    1206      676413 :     if (ret != 0) {
    1207           0 :         *minor_status = ret;
    1208           0 :         return GSS_S_FAILURE;
    1209             :     }
    1210             : 
    1211             :     /* Always rotate encrypted token (if any) and checksum to header */
    1212      676413 :     rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
    1213             : 
    1214      676413 :     output_message_buffer->length = wrapped_len;
    1215      676413 :     output_message_buffer->value = malloc(output_message_buffer->length);
    1216      676413 :     if (output_message_buffer->value == NULL) {
    1217           0 :         *minor_status = ENOMEM;
    1218           0 :         return GSS_S_FAILURE;
    1219             :     }
    1220             : 
    1221      676413 :     p = output_message_buffer->value;
    1222      676413 :     token = (gss_cfx_wrap_token)p;
    1223      676413 :     token->TOK_ID[0] = 0x05;
    1224      676413 :     token->TOK_ID[1] = 0x04;
    1225      676413 :     token->Flags     = 0;
    1226      676413 :     token->Filler    = 0xFF;
    1227      676413 :     if ((ctx->more_flags & LOCAL) == 0)
    1228      340865 :         token->Flags |= CFXSentByAcceptor;
    1229      676413 :     if (ctx->more_flags & ACCEPTOR_SUBKEY)
    1230      676413 :         token->Flags |= CFXAcceptorSubkey;
    1231      676413 :     if (conf_req_flag) {
    1232             :         /*
    1233             :          * In Wrap tokens with confidentiality, the EC field is
    1234             :          * used to encode the size (in bytes) of the random filler.
    1235             :          */
    1236      675759 :         token->Flags |= CFXSealed;
    1237      675759 :         token->EC[0] = (padlength >> 8) & 0xFF;
    1238      675759 :         token->EC[1] = (padlength >> 0) & 0xFF;
    1239             :     } else {
    1240             :         /*
    1241             :          * In Wrap tokens without confidentiality, the EC field is
    1242             :          * used to encode the size (in bytes) of the trailing
    1243             :          * checksum.
    1244             :          *
    1245             :          * This is not used in the checksum calcuation itself,
    1246             :          * because the checksum length could potentially vary
    1247             :          * depending on the data length.
    1248             :          */
    1249         654 :         token->EC[0] = 0;
    1250         654 :         token->EC[1] = 0;
    1251             :     }
    1252             : 
    1253             :     /*
    1254             :      * In Wrap tokens that provide for confidentiality, the RRC
    1255             :      * field in the header contains the hex value 00 00 before
    1256             :      * encryption.
    1257             :      *
    1258             :      * In Wrap tokens that do not provide for confidentiality,
    1259             :      * both the EC and RRC fields in the appended checksum
    1260             :      * contain the hex value 00 00 for the purpose of calculating
    1261             :      * the checksum.
    1262             :      */
    1263      676413 :     token->RRC[0] = 0;
    1264      676413 :     token->RRC[1] = 0;
    1265             : 
    1266         930 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    1267      676413 :     krb5_auth_con_getlocalseqnumber(context,
    1268             :                                     ctx->auth_context,
    1269             :                                     &seq_number);
    1270      676413 :     _gss_mg_encode_be_uint32(0,          &token->SND_SEQ[0]);
    1271      676413 :     _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]);
    1272      676413 :     krb5_auth_con_setlocalseqnumber(context,
    1273             :                                     ctx->auth_context,
    1274             :                                     ++seq_number);
    1275         930 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    1276             : 
    1277             :     /*
    1278             :      * If confidentiality is requested, the token header is
    1279             :      * appended to the plaintext before encryption; the resulting
    1280             :      * token is {"header" | encrypt(plaintext | pad | "header")}.
    1281             :      *
    1282             :      * If no confidentiality is requested, the checksum is
    1283             :      * calculated over the plaintext concatenated with the
    1284             :      * token header.
    1285             :      */
    1286      676413 :     if (ctx->more_flags & LOCAL) {
    1287      335083 :         usage = KRB5_KU_USAGE_INITIATOR_SEAL;
    1288             :     } else {
    1289      340865 :         usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
    1290             :     }
    1291             : 
    1292      676413 :     if (conf_req_flag) {
    1293             :         /*
    1294             :          * Any necessary padding is added here to ensure that the
    1295             :          * encrypted token header is always at the end of the
    1296             :          * ciphertext.
    1297             :          *
    1298             :          * The specification does not require that the padding
    1299             :          * bytes are initialized.
    1300             :          */
    1301      675759 :         p += sizeof(*token);
    1302      675759 :         memcpy(p, input_message_buffer->value, input_message_buffer->length);
    1303      675759 :         memset(p + input_message_buffer->length, 0xFF, padlength);
    1304      675759 :         memcpy(p + input_message_buffer->length + padlength,
    1305             :                token, sizeof(*token));
    1306             : 
    1307      676689 :         ret = krb5_encrypt(context, ctx->crypto,
    1308             :                            usage, p,
    1309      675759 :                            input_message_buffer->length + padlength +
    1310             :                                 sizeof(*token),
    1311             :                            &cipher);
    1312      675759 :         if (ret != 0) {
    1313           0 :             *minor_status = ret;
    1314           0 :             _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1315           0 :             return GSS_S_FAILURE;
    1316             :         }
    1317      675759 :         assert(sizeof(*token) + cipher.length == wrapped_len);
    1318      675759 :         token->RRC[0] = (rrc >> 8) & 0xFF;
    1319      675759 :         token->RRC[1] = (rrc >> 0) & 0xFF;
    1320             : 
    1321             :         /*
    1322             :          * this is really ugly, but needed against windows
    1323             :          * for DCERPC, as windows rotates by EC+RRC.
    1324             :          */
    1325      675759 :         if (IS_DCE_STYLE(ctx)) {
    1326           0 :                 ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
    1327             :         } else {
    1328      675759 :                 ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
    1329             :         }
    1330      675759 :         if (ret != 0) {
    1331           0 :             *minor_status = ret;
    1332           0 :             _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1333           0 :             return GSS_S_FAILURE;
    1334             :         }
    1335      675759 :         memcpy(p, cipher.data, cipher.length);
    1336      675759 :         krb5_data_free(&cipher);
    1337             :     } else {
    1338           0 :         char *buf;
    1339           0 :         Checksum cksum;
    1340             : 
    1341         654 :         buf = malloc(input_message_buffer->length + sizeof(*token));
    1342         654 :         if (buf == NULL) {
    1343           0 :             *minor_status = ENOMEM;
    1344           0 :             _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1345           0 :             return GSS_S_FAILURE;
    1346             :         }
    1347         654 :         memcpy(buf, input_message_buffer->value, input_message_buffer->length);
    1348         654 :         memcpy(buf + input_message_buffer->length, token, sizeof(*token));
    1349             : 
    1350         654 :         ret = krb5_create_checksum(context, ctx->crypto,
    1351             :                                    usage, 0, buf,
    1352         654 :                                    input_message_buffer->length +
    1353             :                                         sizeof(*token),
    1354             :                                    &cksum);
    1355         654 :         if (ret != 0) {
    1356           0 :             *minor_status = ret;
    1357           0 :             _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1358           0 :             free(buf);
    1359           0 :             return GSS_S_FAILURE;
    1360             :         }
    1361             : 
    1362         654 :         free(buf);
    1363             : 
    1364         654 :         assert(cksum.checksum.length == cksumsize);
    1365         654 :         token->EC[0] =  (cksum.checksum.length >> 8) & 0xFF;
    1366         654 :         token->EC[1] =  (cksum.checksum.length >> 0) & 0xFF;
    1367         654 :         token->RRC[0] = (rrc >> 8) & 0xFF;
    1368         654 :         token->RRC[1] = (rrc >> 0) & 0xFF;
    1369             : 
    1370         654 :         p += sizeof(*token);
    1371         654 :         memcpy(p, input_message_buffer->value, input_message_buffer->length);
    1372         654 :         memcpy(p + input_message_buffer->length,
    1373         654 :                cksum.checksum.data, cksum.checksum.length);
    1374             : 
    1375         654 :         ret = rrc_rotate(p,
    1376         654 :             input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
    1377         654 :         if (ret != 0) {
    1378           0 :             *minor_status = ret;
    1379           0 :             _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1380           0 :             free_Checksum(&cksum);
    1381           0 :             return GSS_S_FAILURE;
    1382             :         }
    1383         654 :         free_Checksum(&cksum);
    1384             :     }
    1385             : 
    1386      676413 :     if (conf_state != NULL) {
    1387      676413 :         *conf_state = conf_req_flag;
    1388             :     }
    1389             : 
    1390      676413 :     *minor_status = 0;
    1391      676413 :     return GSS_S_COMPLETE;
    1392             : }
    1393             : 
    1394      676259 : OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
    1395             :                              const gsskrb5_ctx ctx,
    1396             :                              krb5_context context,
    1397             :                              const gss_buffer_t input_message_buffer,
    1398             :                              gss_buffer_t output_message_buffer,
    1399             :                              int *conf_state,
    1400             :                              gss_qop_t *qop_state)
    1401             : {
    1402         930 :     gss_cfx_wrap_token token;
    1403         930 :     u_char token_flags;
    1404         930 :     krb5_error_code ret;
    1405         930 :     unsigned usage;
    1406         930 :     krb5_data data;
    1407         930 :     uint16_t ec, rrc;
    1408         930 :     OM_uint32 seq_number_lo, seq_number_hi;
    1409         930 :     size_t len;
    1410         930 :     u_char *p;
    1411             : 
    1412      676259 :     *minor_status = 0;
    1413             : 
    1414      676259 :     if (input_message_buffer->length < sizeof(*token)) {
    1415           0 :         return GSS_S_DEFECTIVE_TOKEN;
    1416             :     }
    1417             : 
    1418      676259 :     p = input_message_buffer->value;
    1419             : 
    1420      676259 :     token = (gss_cfx_wrap_token)p;
    1421             : 
    1422      676259 :     if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
    1423           0 :         return GSS_S_DEFECTIVE_TOKEN;
    1424             :     }
    1425             : 
    1426             :     /* Ignore unknown flags */
    1427      676259 :     token_flags = token->Flags &
    1428             :         (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
    1429             : 
    1430      676259 :     if (token_flags & CFXSentByAcceptor) {
    1431      340657 :         if ((ctx->more_flags & LOCAL) == 0)
    1432           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1433             :     }
    1434             : 
    1435      676259 :     if (ctx->more_flags & ACCEPTOR_SUBKEY) {
    1436      676259 :         if ((token_flags & CFXAcceptorSubkey) == 0)
    1437           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1438             :     } else {
    1439           0 :         if (token_flags & CFXAcceptorSubkey)
    1440           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1441             :     }
    1442             : 
    1443      676259 :     if (token->Filler != 0xFF) {
    1444           0 :         return GSS_S_DEFECTIVE_TOKEN;
    1445             :     }
    1446             : 
    1447      676259 :     if (conf_state != NULL) {
    1448      676259 :         *conf_state = (token_flags & CFXSealed) ? 1 : 0;
    1449             :     }
    1450             : 
    1451      676259 :     ec  = (token->EC[0]  << 8) | token->EC[1];
    1452      676259 :     rrc = (token->RRC[0] << 8) | token->RRC[1];
    1453             : 
    1454             :     /*
    1455             :      * Check sequence number
    1456             :      */
    1457      676259 :     _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi);
    1458      676259 :     _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo);
    1459      676259 :     if (seq_number_hi) {
    1460             :         /* no support for 64-bit sequence numbers */
    1461           0 :         *minor_status = ERANGE;
    1462           0 :         return GSS_S_UNSEQ_TOKEN;
    1463             :     }
    1464             : 
    1465         930 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    1466      676259 :     ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
    1467      676259 :     if (ret != 0) {
    1468           0 :         *minor_status = 0;
    1469           0 :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    1470           0 :         _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1471           0 :         return ret;
    1472             :     }
    1473         930 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    1474             : 
    1475             :     /*
    1476             :      * Decrypt and/or verify checksum
    1477             :      */
    1478             : 
    1479      676259 :     if (ctx->more_flags & LOCAL) {
    1480      340192 :         usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
    1481             :     } else {
    1482      335602 :         usage = KRB5_KU_USAGE_INITIATOR_SEAL;
    1483             :     }
    1484             : 
    1485      676259 :     p += sizeof(*token);
    1486      676259 :     len = input_message_buffer->length;
    1487      676259 :     len -= (p - (u_char *)input_message_buffer->value);
    1488             : 
    1489      676259 :     if (token_flags & CFXSealed) {
    1490             :         /*
    1491             :          * this is really ugly, but needed against windows
    1492             :          * for DCERPC, as windows rotates by EC+RRC.
    1493             :          */
    1494      675605 :         if (IS_DCE_STYLE(ctx)) {
    1495           0 :                 *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
    1496             :         } else {
    1497      675605 :                 *minor_status = rrc_rotate(p, len, rrc, TRUE);
    1498             :         }
    1499      675605 :         if (*minor_status != 0) {
    1500           0 :             return GSS_S_FAILURE;
    1501             :         }
    1502             : 
    1503      675605 :         ret = krb5_decrypt(context, ctx->crypto, usage,
    1504             :             p, len, &data);
    1505      675605 :         if (ret != 0) {
    1506           0 :             *minor_status = ret;
    1507           0 :             return GSS_S_BAD_MIC;
    1508             :         }
    1509             : 
    1510             :         /* Check that there is room for the pad and token header */
    1511      675605 :         if (data.length < ec + sizeof(*token)) {
    1512           0 :             krb5_data_free(&data);
    1513           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1514             :         }
    1515      675605 :         p = data.data;
    1516      675605 :         p += data.length - sizeof(*token);
    1517             : 
    1518             :         /* RRC is unprotected; don't modify input buffer */
    1519      675605 :         ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
    1520      675605 :         ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
    1521             : 
    1522             :         /* Check the integrity of the header */
    1523      675605 :         if (ct_memcmp(p, token, sizeof(*token)) != 0) {
    1524           0 :             krb5_data_free(&data);
    1525           0 :             return GSS_S_BAD_MIC;
    1526             :         }
    1527             : 
    1528      675605 :         output_message_buffer->value = data.data;
    1529      675605 :         output_message_buffer->length = data.length - ec - sizeof(*token);
    1530             :     } else {
    1531           0 :         Checksum cksum;
    1532             : 
    1533             :         /* Rotate by RRC; bogus to do this in-place XXX */
    1534         654 :         *minor_status = rrc_rotate(p, len, rrc, TRUE);
    1535         654 :         if (*minor_status != 0) {
    1536           0 :             return GSS_S_FAILURE;
    1537             :         }
    1538             : 
    1539             :         /* Determine checksum type */
    1540         654 :         ret = krb5_crypto_get_checksum_type(context,
    1541             :                                             ctx->crypto,
    1542             :                                             &cksum.cksumtype);
    1543         654 :         if (ret != 0) {
    1544           0 :             *minor_status = ret;
    1545           0 :             return GSS_S_FAILURE;
    1546             :         }
    1547             : 
    1548         654 :         cksum.checksum.length = ec;
    1549             : 
    1550             :         /* Check we have at least as much data as the checksum */
    1551         654 :         if (len < cksum.checksum.length) {
    1552           0 :             *minor_status = ERANGE;
    1553           0 :             return GSS_S_BAD_MIC;
    1554             :         }
    1555             : 
    1556             :         /* Length now is of the plaintext only, no checksum */
    1557         654 :         len -= cksum.checksum.length;
    1558         654 :         cksum.checksum.data = p + len;
    1559             : 
    1560         654 :         output_message_buffer->length = len; /* for later */
    1561         654 :         output_message_buffer->value = malloc(len + sizeof(*token));
    1562         654 :         if (output_message_buffer->value == NULL) {
    1563           0 :             *minor_status = ENOMEM;
    1564           0 :             return GSS_S_FAILURE;
    1565             :         }
    1566             : 
    1567             :         /* Checksum is over (plaintext-data | "header") */
    1568         654 :         memcpy(output_message_buffer->value, p, len);
    1569         654 :         memcpy((u_char *)output_message_buffer->value + len,
    1570             :                token, sizeof(*token));
    1571             : 
    1572             :         /* EC is not included in checksum calculation */
    1573         654 :         token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
    1574             :                                      len);
    1575         654 :         token->EC[0]  = 0;
    1576         654 :         token->EC[1]  = 0;
    1577         654 :         token->RRC[0] = 0;
    1578         654 :         token->RRC[1] = 0;
    1579             : 
    1580         654 :         ret = krb5_verify_checksum(context, ctx->crypto,
    1581             :                                    usage,
    1582             :                                    output_message_buffer->value,
    1583             :                                    len + sizeof(*token),
    1584             :                                    &cksum);
    1585         654 :         if (ret != 0) {
    1586           0 :             *minor_status = ret;
    1587           0 :             _gsskrb5_release_buffer(minor_status, output_message_buffer);
    1588           0 :             return GSS_S_BAD_MIC;
    1589             :         }
    1590             :     }
    1591             : 
    1592      676259 :     if (qop_state != NULL) {
    1593      676259 :         *qop_state = GSS_C_QOP_DEFAULT;
    1594             :     }
    1595             : 
    1596      676259 :     *minor_status = 0;
    1597      676259 :     return GSS_S_COMPLETE;
    1598             : }
    1599             : 
    1600      239672 : OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
    1601             :                           const gsskrb5_ctx ctx,
    1602             :                           krb5_context context,
    1603             :                           gss_qop_t qop_req,
    1604             :                           const gss_buffer_t message_buffer,
    1605             :                           gss_buffer_t message_token)
    1606             : {
    1607         316 :     gss_cfx_mic_token token;
    1608         316 :     krb5_error_code ret;
    1609         316 :     unsigned usage;
    1610         316 :     Checksum cksum;
    1611         316 :     u_char *buf;
    1612         316 :     size_t len;
    1613         316 :     int32_t seq_number;
    1614             : 
    1615      239672 :     len = message_buffer->length + sizeof(*token);
    1616      239672 :     buf = malloc(len);
    1617      239672 :     if (buf == NULL) {
    1618           0 :         *minor_status = ENOMEM;
    1619           0 :         return GSS_S_FAILURE;
    1620             :     }
    1621             : 
    1622      239672 :     if (message_buffer->length)
    1623      239552 :         memcpy(buf, message_buffer->value, message_buffer->length);
    1624             :     else
    1625         120 :         memset(buf, 0, len);
    1626             : 
    1627      239672 :     token = (gss_cfx_mic_token)(buf + message_buffer->length);
    1628      239672 :     token->TOK_ID[0] = 0x04;
    1629      239672 :     token->TOK_ID[1] = 0x04;
    1630      239672 :     token->Flags = 0;
    1631      239672 :     if ((ctx->more_flags & LOCAL) == 0)
    1632      220801 :         token->Flags |= CFXSentByAcceptor;
    1633      239672 :     if (ctx->more_flags & ACCEPTOR_SUBKEY)
    1634      239672 :         token->Flags |= CFXAcceptorSubkey;
    1635      239672 :     memset(token->Filler, 0xFF, 5);
    1636             : 
    1637         316 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    1638      239672 :     krb5_auth_con_getlocalseqnumber(context,
    1639             :                                     ctx->auth_context,
    1640             :                                     &seq_number);
    1641      239672 :     _gss_mg_encode_be_uint32(0,          &token->SND_SEQ[0]);
    1642      239672 :     _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]);
    1643      239672 :     krb5_auth_con_setlocalseqnumber(context,
    1644             :                                     ctx->auth_context,
    1645             :                                     ++seq_number);
    1646         316 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    1647             : 
    1648      239672 :     if (ctx->more_flags & LOCAL) {
    1649       18713 :         usage = KRB5_KU_USAGE_INITIATOR_SIGN;
    1650             :     } else {
    1651      220801 :         usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
    1652             :     }
    1653             : 
    1654      239672 :     ret = krb5_create_checksum(context, ctx->crypto,
    1655             :         usage, 0, buf, len, &cksum);
    1656      239672 :     if (ret != 0) {
    1657           0 :         *minor_status = ret;
    1658           0 :         free(buf);
    1659           0 :         return GSS_S_FAILURE;
    1660             :     }
    1661             : 
    1662             :     /* Determine MIC length */
    1663      239672 :     message_token->length = sizeof(*token) + cksum.checksum.length;
    1664      239672 :     message_token->value = malloc(message_token->length);
    1665      239672 :     if (message_token->value == NULL) {
    1666           0 :         *minor_status = ENOMEM;
    1667           0 :         free_Checksum(&cksum);
    1668           0 :         free(buf);
    1669           0 :         return GSS_S_FAILURE;
    1670             :     }
    1671             : 
    1672             :     /* Token is { "header" | get_mic("header" | plaintext-data) } */
    1673      239672 :     memcpy(message_token->value, token, sizeof(*token));
    1674      239672 :     memcpy((u_char *)message_token->value + sizeof(*token),
    1675      239672 :            cksum.checksum.data, cksum.checksum.length);
    1676             : 
    1677      239672 :     free_Checksum(&cksum);
    1678      239672 :     free(buf);
    1679             : 
    1680      239672 :     *minor_status = 0;
    1681      239672 :     return GSS_S_COMPLETE;
    1682             : }
    1683             : 
    1684      239957 : OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
    1685             :                                  const gsskrb5_ctx ctx,
    1686             :                                  krb5_context context,
    1687             :                                  const gss_buffer_t message_buffer,
    1688             :                                  const gss_buffer_t token_buffer,
    1689             :                                  gss_qop_t *qop_state)
    1690             : {
    1691         316 :     gss_cfx_mic_token token;
    1692         316 :     u_char token_flags;
    1693         316 :     krb5_error_code ret;
    1694         316 :     unsigned usage;
    1695         316 :     OM_uint32 seq_number_lo, seq_number_hi;
    1696         316 :     u_char *buf, *p;
    1697         316 :     Checksum cksum;
    1698             : 
    1699      239957 :     *minor_status = 0;
    1700             : 
    1701      239957 :     if (token_buffer->length < sizeof(*token)) {
    1702           1 :         return GSS_S_DEFECTIVE_TOKEN;
    1703             :     }
    1704             : 
    1705      239956 :     p = token_buffer->value;
    1706             : 
    1707      239956 :     token = (gss_cfx_mic_token)p;
    1708             : 
    1709      239956 :     if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
    1710           0 :         return GSS_S_DEFECTIVE_TOKEN;
    1711             :     }
    1712             : 
    1713             :     /* Ignore unknown flags */
    1714      239956 :     token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
    1715             : 
    1716      239956 :     if (token_flags & CFXSentByAcceptor) {
    1717       18747 :         if ((ctx->more_flags & LOCAL) == 0)
    1718           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1719             :     }
    1720      239956 :     if (ctx->more_flags & ACCEPTOR_SUBKEY) {
    1721      239956 :         if ((token_flags & CFXAcceptorSubkey) == 0)
    1722           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1723             :     } else {
    1724           0 :         if (token_flags & CFXAcceptorSubkey)
    1725           0 :             return GSS_S_DEFECTIVE_TOKEN;
    1726             :     }
    1727             : 
    1728      239956 :     if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
    1729           0 :         return GSS_S_DEFECTIVE_TOKEN;
    1730             :     }
    1731             : 
    1732             :     /*
    1733             :      * Check sequence number
    1734             :      */
    1735      239956 :     _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi);
    1736      239956 :     _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo);
    1737      239956 :     if (seq_number_hi) {
    1738           0 :         *minor_status = ERANGE;
    1739           0 :         return GSS_S_UNSEQ_TOKEN;
    1740             :     }
    1741             : 
    1742         316 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
    1743      239956 :     ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
    1744      239956 :     if (ret != 0) {
    1745           0 :         *minor_status = 0;
    1746           0 :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    1747           0 :         return ret;
    1748             :     }
    1749         316 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    1750             : 
    1751             :     /*
    1752             :      * Verify checksum
    1753             :      */
    1754      239956 :     ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
    1755             :                                         &cksum.cksumtype);
    1756      239956 :     if (ret != 0) {
    1757           0 :         *minor_status = ret;
    1758           0 :         return GSS_S_FAILURE;
    1759             :     }
    1760             : 
    1761      239956 :     cksum.checksum.data = p + sizeof(*token);
    1762      239956 :     cksum.checksum.length = token_buffer->length - sizeof(*token);
    1763             : 
    1764      239956 :     if (ctx->more_flags & LOCAL) {
    1765       18589 :         usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
    1766             :     } else {
    1767      221209 :         usage = KRB5_KU_USAGE_INITIATOR_SIGN;
    1768             :     }
    1769             : 
    1770      239956 :     buf = malloc(message_buffer->length + sizeof(*token));
    1771      239956 :     if (buf == NULL) {
    1772           0 :         *minor_status = ENOMEM;
    1773           0 :         return GSS_S_FAILURE;
    1774             :     }
    1775      239956 :     if (message_buffer->length)
    1776      239878 :         memcpy(buf, message_buffer->value, message_buffer->length);
    1777      239956 :     memcpy(buf + message_buffer->length, token, sizeof(*token));
    1778             : 
    1779      239956 :     ret = krb5_verify_checksum(context, ctx->crypto,
    1780             :                                usage,
    1781             :                                buf,
    1782      239640 :                                sizeof(*token) + message_buffer->length,
    1783             :                                &cksum);
    1784      239956 :     if (ret != 0) {
    1785          20 :         *minor_status = ret;
    1786          20 :         free(buf);
    1787          20 :         return GSS_S_BAD_MIC;
    1788             :     }
    1789             : 
    1790      239936 :     free(buf);
    1791             : 
    1792      239936 :     if (qop_state != NULL) {
    1793      239936 :         *qop_state = GSS_C_QOP_DEFAULT;
    1794             :     }
    1795             : 
    1796      239620 :     return GSS_S_COMPLETE;
    1797             : }

Generated by: LCOV version 1.14