Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: 8003.c,v 1.2 2017/01/28 21:31:46 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2003 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "gsskrb5_locl.h"
     37 
     38 krb5_error_code
     39 _gsskrb5_encode_om_uint32(OM_uint32 n, u_char *p)
     40 {
     41   p[0] = (n >> 0)  & 0xFF;
     42   p[1] = (n >> 8)  & 0xFF;
     43   p[2] = (n >> 16) & 0xFF;
     44   p[3] = (n >> 24) & 0xFF;
     45   return 0;
     46 }
     47 
     48 krb5_error_code
     49 _gsskrb5_encode_be_om_uint32(OM_uint32 n, u_char *p)
     50 {
     51   p[0] = (n >> 24) & 0xFF;
     52   p[1] = (n >> 16) & 0xFF;
     53   p[2] = (n >> 8)  & 0xFF;
     54   p[3] = (n >> 0)  & 0xFF;
     55   return 0;
     56 }
     57 
     58 krb5_error_code
     59 _gsskrb5_decode_om_uint32(const void *ptr, OM_uint32 *n)
     60 {
     61     const u_char *p = ptr;
     62     *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
     63     return 0;
     64 }
     65 
     66 krb5_error_code
     67 _gsskrb5_decode_be_om_uint32(const void *ptr, OM_uint32 *n)
     68 {
     69     const u_char *p = ptr;
     70     *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
     71     return 0;
     72 }
     73 
     74 static krb5_error_code
     75 hash_input_chan_bindings (const gss_channel_bindings_t b,
     76 			  u_char *p)
     77 {
     78   u_char num[4];
     79   EVP_MD_CTX *ctx;
     80 
     81   ctx = EVP_MD_CTX_create();
     82   EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
     83 
     84   _gsskrb5_encode_om_uint32 (b->initiator_addrtype, num);
     85   EVP_DigestUpdate(ctx, num, sizeof(num));
     86   _gsskrb5_encode_om_uint32 (b->initiator_address.length, num);
     87   EVP_DigestUpdate(ctx, num, sizeof(num));
     88   if (b->initiator_address.length)
     89       EVP_DigestUpdate(ctx,
     90 		       b->initiator_address.value,
     91 		       b->initiator_address.length);
     92   _gsskrb5_encode_om_uint32 (b->acceptor_addrtype, num);
     93   EVP_DigestUpdate(ctx, num, sizeof(num));
     94   _gsskrb5_encode_om_uint32 (b->acceptor_address.length, num);
     95   EVP_DigestUpdate(ctx, num, sizeof(num));
     96   if (b->acceptor_address.length)
     97       EVP_DigestUpdate(ctx,
     98 		       b->acceptor_address.value,
     99 		       b->acceptor_address.length);
    100   _gsskrb5_encode_om_uint32 (b->application_data.length, num);
    101   EVP_DigestUpdate(ctx, num, sizeof(num));
    102   if (b->application_data.length)
    103       EVP_DigestUpdate(ctx,
    104 		       b->application_data.value,
    105 		       b->application_data.length);
    106   EVP_DigestFinal_ex(ctx, p, NULL);
    107   EVP_MD_CTX_destroy(ctx);
    108 
    109   return 0;
    110 }
    111 
    112 /*
    113  * create a checksum over the chanel bindings in
    114  * `input_chan_bindings', `flags' and `fwd_data' and return it in
    115  * `result'
    116  */
    117 
    118 OM_uint32
    119 _gsskrb5_create_8003_checksum (
    120 		      OM_uint32 *minor_status,
    121 		      const gss_channel_bindings_t input_chan_bindings,
    122 		      OM_uint32 flags,
    123 		      const krb5_data *fwd_data,
    124 		      Checksum *result)
    125 {
    126     u_char *p;
    127 
    128     /*
    129      * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value
    130      * field's format) */
    131     result->cksumtype = CKSUMTYPE_GSSAPI;
    132     if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG))
    133 	result->checksum.length = 24 + 4 + fwd_data->length;
    134     else
    135 	result->checksum.length = 24;
    136     result->checksum.data   = malloc (result->checksum.length);
    137     if (result->checksum.data == NULL) {
    138 	*minor_status = ENOMEM;
    139 	return GSS_S_FAILURE;
    140     }
    141 
    142     p = result->checksum.data;
    143     _gsskrb5_encode_om_uint32 (16, p);
    144     p += 4;
    145     if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) {
    146 	memset (p, 0, 16);
    147     } else {
    148 	hash_input_chan_bindings (input_chan_bindings, p);
    149     }
    150     p += 16;
    151     _gsskrb5_encode_om_uint32 (flags, p);
    152     p += 4;
    153 
    154     if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) {
    155 
    156 	*p++ = (1 >> 0) & 0xFF;                   /* DlgOpt */ /* == 1 */
    157 	*p++ = (1 >> 8) & 0xFF;                   /* DlgOpt */ /* == 0 */
    158 	*p++ = (fwd_data->length >> 0) & 0xFF;    /* Dlgth  */
    159 	*p++ = (fwd_data->length >> 8) & 0xFF;    /* Dlgth  */
    160 	memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length);
    161 
    162 	/* p += fwd_data->length; */ /* commented out to quiet warning */
    163     }
    164 
    165     return GSS_S_COMPLETE;
    166 }
    167 
    168 /*
    169  * verify the checksum in `cksum' over `input_chan_bindings'
    170  * returning  `flags' and `fwd_data'
    171  */
    172 
    173 OM_uint32
    174 _gsskrb5_verify_8003_checksum(
    175 		      OM_uint32 *minor_status,
    176 		      const gss_channel_bindings_t input_chan_bindings,
    177 		      const Checksum *cksum,
    178 		      OM_uint32 *flags,
    179 		      krb5_data *fwd_data)
    180 {
    181     unsigned char hash[16];
    182     unsigned char *p;
    183     OM_uint32 length;
    184     int DlgOpt;
    185     static unsigned char zeros[16];
    186 
    187     /* XXX should handle checksums > 24 bytes */
    188     if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) {
    189 	*minor_status = 0;
    190 	return GSS_S_BAD_BINDINGS;
    191     }
    192 
    193     p = cksum->checksum.data;
    194     _gsskrb5_decode_om_uint32(p, &length);
    195     if(length != sizeof(hash)) {
    196 	*minor_status = 0;
    197 	return GSS_S_BAD_BINDINGS;
    198     }
    199 
    200     p += 4;
    201 
    202     if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
    203 	&& memcmp(p, zeros, sizeof(zeros)) != 0) {
    204 	if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) {
    205 	    *minor_status = 0;
    206 	    return GSS_S_BAD_BINDINGS;
    207 	}
    208 	if(ct_memcmp(hash, p, sizeof(hash)) != 0) {
    209 	    *minor_status = 0;
    210 	    return GSS_S_BAD_BINDINGS;
    211 	}
    212     }
    213 
    214     p += sizeof(hash);
    215 
    216     _gsskrb5_decode_om_uint32(p, flags);
    217     p += 4;
    218 
    219     if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) {
    220 	if(cksum->checksum.length < 28) {
    221 	    *minor_status = 0;
    222 	    return GSS_S_BAD_BINDINGS;
    223 	}
    224 
    225 	DlgOpt = (p[0] << 0) | (p[1] << 8);
    226 	p += 2;
    227 	if (DlgOpt != 1) {
    228 	    *minor_status = 0;
    229 	    return GSS_S_BAD_BINDINGS;
    230 	}
    231 
    232 	fwd_data->length = (p[0] << 0) | (p[1] << 8);
    233 	p += 2;
    234 	if(cksum->checksum.length < 28 + fwd_data->length) {
    235 	    *minor_status = 0;
    236 	    return GSS_S_BAD_BINDINGS;
    237 	}
    238 	fwd_data->data = malloc(fwd_data->length);
    239 	if (fwd_data->data == NULL) {
    240 	    *minor_status = ENOMEM;
    241 	    return GSS_S_FAILURE;
    242 	}
    243 	memcpy(fwd_data->data, p, fwd_data->length);
    244     }
    245 
    246     return GSS_S_COMPLETE;
    247 }
    248