1/* 2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "gsskrb5_locl.h" 35 36krb5_error_code 37_gsskrb5_decode_be_om_uint32(const void *ptr, OM_uint32 *n) 38{ 39 const u_char *p = ptr; 40 *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); 41 return 0; 42} 43 44/* 45 * 46 */ 47 48static OM_uint32 49store_ext(krb5_storage *sp, uint16_t type, krb5_data *data) 50{ 51 krb5_error_code ret; 52 krb5_ssize_t sret; 53 54 ret = krb5_store_uint16(sp, type); 55 if (ret) return ret; 56 ret = krb5_store_uint16(sp, data->length); 57 if (ret) return ret; 58 sret = krb5_storage_write(sp, data->data, data->length); 59 if (sret < 0 || (size_t)sret != data->length) 60 return ENOMEM; 61 return 0; 62} 63 64/* 65 * create a checksum over the chanel bindings in 66 * `input_chan_bindings', `flags' and `fwd_data' and return it in 67 * `result' 68 */ 69 70OM_uint32 71_gsskrb5_create_8003_checksum(OM_uint32 *minor_status, 72 krb5_context context, 73 krb5_crypto crypto, 74 const gss_channel_bindings_t input_chan_bindings, 75 OM_uint32 flags, 76 krb5_data *fwd_data, 77 krb5_data *pkt_cksum, 78 Checksum *result) 79{ 80 uint8_t channelbindings[16]; 81 gss_buffer_desc cksum; 82 krb5_error_code ret; 83 krb5_storage *sp; 84 OM_uint32 maj_stat, junk; 85 krb5_ssize_t sret; 86 87 cksum.value = NULL; 88 cksum.length = 0; 89 90 sp = krb5_storage_emem(); 91 if (sp == NULL) { 92 ret = ENOMEM; 93 goto out; 94 } 95 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 96 97 ret = krb5_store_uint32(sp, 16); 98 if (ret) goto out; 99 100 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) { 101 memset (channelbindings, 0, 16); 102 } else { 103 maj_stat = gss_mg_gen_cb(minor_status, input_chan_bindings, channelbindings, &cksum); 104 if (maj_stat) { 105 ret = *minor_status; 106 goto out; 107 } 108 } 109 sret = krb5_storage_write(sp, channelbindings, sizeof(channelbindings)); 110 if (sret != sizeof(channelbindings)) { 111 ret = ENOMEM; 112 goto out; 113 } 114 ret = krb5_store_uint32(sp, flags); 115 if (ret) goto out; 116 117 if (flags & GSS_C_DELEG_FLAG) { 118 ret = store_ext(sp, 1, fwd_data); 119 if (ret) goto out; 120 } 121 if (pkt_cksum->length > 0) { 122 ret = store_ext(sp, 2, pkt_cksum); 123 if (ret) goto out; 124 } 125 126 if (crypto && input_chan_bindings && cksum.length) { 127 Checksum checksum; 128 krb5_data data; 129 size_t size = 0; 130 131 memset(&checksum, 0, sizeof(checksum)); 132 ret = krb5_create_checksum(context, crypto, KRB5_KU_GSSAPI_EXTS, 0, 133 cksum.value, cksum.length, &checksum); 134 if (ret) goto out; 135 136 ASN1_MALLOC_ENCODE(Checksum, data.data, data.length, 137 &checksum, &size, ret); 138 if (ret) 139 goto out; 140 if (data.length != size) 141 krb5_abortx(context, "internal error in ASN.1 encoder"); 142 143 ret = store_ext(sp, 0, &data); 144 krb5_data_free(&data); 145 if (ret) goto out; 146 } 147 148 /* 149 * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value 150 * field's format) 151 */ 152 result->cksumtype = CKSUMTYPE_GSSAPI; 153 ret = krb5_storage_to_data(sp, &result->checksum); 154 out: 155 gss_release_buffer(&junk, &cksum); 156 if (sp) 157 krb5_storage_free(sp); 158 if (ret) { 159 *minor_status = ret; 160 return GSS_S_FAILURE; 161 } 162 163 return GSS_S_COMPLETE; 164} 165 166/* 167 * 168 */ 169 170static krb5_error_code 171read_ext(krb5_storage *sp, uint16_t *type, krb5_data *data) 172{ 173 krb5_error_code ret; 174 krb5_ssize_t sret; 175 uint16_t len; 176 177 ret = krb5_ret_uint16(sp, type); 178 if (ret) 179 return ret; 180 181 ret = krb5_ret_uint16(sp, &len); 182 if (ret) 183 return ret; 184 185 ret = krb5_data_alloc(data, len); 186 if (ret) 187 return ret; 188 189 sret = krb5_storage_read(sp, data->data, data->length); 190 if (sret < 0 || (size_t)sret != data->length) { 191 krb5_data_free(data); 192 return HEIM_ERR_EOF; 193 } 194 return 0; 195} 196 197/* 198 * verify the checksum in `cksum' over `input_chan_bindings' 199 * returning `flags' and `fwd_data' 200 */ 201 202OM_uint32 203_gsskrb5_verify_8003_checksum(OM_uint32 *minor_status, 204 krb5_context context, 205 krb5_crypto crypto, 206 const gss_channel_bindings_t input_chan_bindings, 207 const Checksum *cksum, 208 OM_uint32 *flags, 209 krb5_data *fwd_data, 210 krb5_data *finished) 211{ 212 unsigned count = 0, verified_checksum = 0; 213 krb5_error_code ret; 214 krb5_ssize_t sret; 215 krb5_storage *sp; 216 unsigned char hash[16], pkthash[16]; 217 uint32_t length; 218 krb5_data data; 219 uint16_t type; 220 OM_uint32 maj_stat, junk; 221 gss_buffer_desc cbdata; 222 223 cbdata.length = 0; 224 krb5_data_zero(&data); 225 226 /* XXX should handle checksums > 24 bytes */ 227 if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) { 228 *minor_status = 0; 229 return GSS_S_BAD_BINDINGS; 230 } 231 232 sp = krb5_storage_from_readonly_mem(cksum->checksum.data, 233 cksum->checksum.length); 234 if (sp == NULL) { 235 *minor_status = ENOMEM; 236 return GSS_S_FAILURE; 237 } 238 krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 239 240 ret = krb5_ret_uint32(sp, &length); 241 if (ret) goto out; 242 if(length != sizeof(hash)) { 243 ret = ENOMEM; 244 goto out; 245 } 246 247 sret = krb5_storage_read(sp, pkthash, sizeof(pkthash)); 248 if (sret != sizeof(pkthash)) { 249 ret = ENOMEM; 250 goto out; 251 } 252 253 maj_stat = gss_mg_validate_cb(minor_status, input_chan_bindings, 254 pkthash, &cbdata); 255 if (maj_stat) { 256 ret = *minor_status; 257 goto out; 258 } 259 260 ret = krb5_ret_uint32(sp, flags); 261 if (ret) goto out; 262 263 if ((*flags) & GSS_C_DELEG_FLAG) { 264 ret = read_ext(sp, &type, fwd_data); 265 if (ret) goto out; 266 267 if (type != 1) { 268 ret = EINVAL; 269 goto out; 270 } 271 } 272 273 while ((ret = read_ext(sp, &type, &data)) == 0) { 274 count++; 275 if (type == 0 && input_chan_bindings) { 276 Checksum checksum; 277 278 /* new checksum */ 279 280 if (crypto == NULL) { 281 ret = ENOMEM; 282 goto out; 283 } 284 285 ret = decode_Checksum(data.data, data.length, &checksum, NULL); 286 if (ret) goto out; 287 288 ret = krb5_verify_checksum(context, crypto, KRB5_KU_GSSAPI_EXTS, 289 cbdata.value, cbdata.length, 290 &checksum); 291 free_Checksum(&checksum); 292 krb5_data_free(&data); 293 294 if (ret) goto out; 295 296 verified_checksum = 1; 297 298 } else if (type == 2) { 299 *finished = data; 300 krb5_data_zero(&data); 301 } else 302 krb5_data_free(&data); 303 } 304 if (ret != HEIM_ERR_EOF && ret != 0) 305 goto out; 306 307 if (input_chan_bindings && count && !verified_checksum) { 308 ret = EINVAL; 309 goto out; 310 } 311 ret = 0; 312 313 out: 314 gss_release_buffer(&junk, &cbdata); 315 krb5_data_free(&data); 316 krb5_storage_free(sp); 317 if (ret) { 318 *minor_status = ret; 319 return GSS_S_BAD_BINDINGS; 320 } 321 return GSS_S_COMPLETE; 322} 323