1/* 2 * Copyright (c) 1997 - 2007 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 "krb5_locl.h" 35 36static krb5_error_code 37compare_addrs(krb5_context context, 38 krb5_address *a, 39 krb5_address *b, 40 const char *message) 41{ 42 char a_str[64], b_str[64]; 43 size_t len; 44 45 if(krb5_address_compare (context, a, b)) 46 return 0; 47 48 krb5_print_address (a, a_str, sizeof(a_str), &len); 49 krb5_print_address (b, b_str, sizeof(b_str), &len); 50 krb5_set_error_message(context, KRB5KRB_AP_ERR_BADADDR, 51 "%s: %s != %s", message, b_str, a_str); 52 return KRB5KRB_AP_ERR_BADADDR; 53} 54 55KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 56krb5_rd_cred(krb5_context context, 57 krb5_auth_context auth_context, 58 krb5_data *in_data, 59 krb5_creds ***ret_creds, 60 krb5_replay_data *outdata) 61{ 62 krb5_error_code ret; 63 size_t len; 64 KRB_CRED cred; 65 EncKrbCredPart enc_krb_cred_part; 66 krb5_data enc_krb_cred_part_data; 67 krb5_crypto crypto; 68 size_t i; 69 70 memset(&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); 71 krb5_data_zero(&enc_krb_cred_part_data); 72 73 if ((auth_context->flags & 74 (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 75 outdata == NULL) 76 return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */ 77 78 *ret_creds = NULL; 79 80 ret = decode_KRB_CRED(in_data->data, in_data->length, 81 &cred, &len); 82 if(ret) { 83 krb5_clear_error_message(context); 84 return ret; 85 } 86 87 if (cred.pvno != 5) { 88 ret = KRB5KRB_AP_ERR_BADVERSION; 89 krb5_clear_error_message (context); 90 goto out; 91 } 92 93 if (cred.msg_type != krb_cred) { 94 ret = KRB5KRB_AP_ERR_MSG_TYPE; 95 krb5_clear_error_message (context); 96 goto out; 97 } 98 99 if (cred.enc_part.etype == ETYPE_NULL) { 100 /* DK: MIT GSS-API Compatibility */ 101 enc_krb_cred_part_data.length = cred.enc_part.cipher.length; 102 enc_krb_cred_part_data.data = cred.enc_part.cipher.data; 103 } else { 104 /* Try both subkey and session key. 105 * 106 * RFC4120 claims we should use the session key, but Heimdal 107 * before 0.8 used the remote subkey if it was send in the 108 * auth_context. 109 */ 110 111 ret = krb5_crypto_init(context, auth_context->keyblock, 112 0, &crypto); 113 114 if (ret) 115 goto out; 116 117 ret = krb5_decrypt_EncryptedData(context, 118 crypto, 119 KRB5_KU_KRB_CRED, 120 &cred.enc_part, 121 &enc_krb_cred_part_data); 122 123 krb5_crypto_destroy(context, crypto); 124 125 /* 126 * Retry using the subkey if we failed 127 */ 128 if (ret && auth_context->remote_subkey) { 129 ret = krb5_crypto_init(context, auth_context->remote_subkey, 130 0, &crypto); 131 if (ret) 132 goto out; 133 134 ret = krb5_decrypt_EncryptedData(context, 135 crypto, 136 KRB5_KU_KRB_CRED, 137 &cred.enc_part, 138 &enc_krb_cred_part_data); 139 140 krb5_crypto_destroy(context, crypto); 141 } 142 if (ret) 143 goto out; 144 } 145 146 ret = decode_EncKrbCredPart(enc_krb_cred_part_data.data, 147 enc_krb_cred_part_data.length, 148 &enc_krb_cred_part, 149 &len); 150 if (enc_krb_cred_part_data.data != cred.enc_part.cipher.data) 151 krb5_data_free(&enc_krb_cred_part_data); 152 if (ret) { 153 krb5_set_error_message(context, ret, 154 N_("Failed to decode " 155 "encrypte credential part", "")); 156 goto out; 157 } 158 159 /* check sender address */ 160 161 if (enc_krb_cred_part.s_address 162 && auth_context->remote_address 163 && auth_context->remote_port) { 164 krb5_address *a; 165 166 ret = krb5_make_addrport (context, &a, 167 auth_context->remote_address, 168 auth_context->remote_port); 169 if (ret) 170 goto out; 171 172 173 ret = compare_addrs(context, a, enc_krb_cred_part.s_address, 174 N_("sender address is wrong " 175 "in received creds", "")); 176 krb5_free_address(context, a); 177 free(a); 178 if(ret) 179 goto out; 180 } 181 182 /* check receiver address */ 183 184 if (enc_krb_cred_part.r_address 185 && auth_context->local_address) { 186 if(auth_context->local_port && 187 enc_krb_cred_part.r_address->addr_type == KRB5_ADDRESS_ADDRPORT) { 188 krb5_address *a; 189 ret = krb5_make_addrport (context, &a, 190 auth_context->local_address, 191 auth_context->local_port); 192 if (ret) 193 goto out; 194 195 ret = compare_addrs(context, a, enc_krb_cred_part.r_address, 196 N_("receiver address is wrong " 197 "in received creds", "")); 198 krb5_free_address(context, a); 199 free(a); 200 if(ret) 201 goto out; 202 } else { 203 ret = compare_addrs(context, auth_context->local_address, 204 enc_krb_cred_part.r_address, 205 N_("receiver address is wrong " 206 "in received creds", "")); 207 if(ret) 208 goto out; 209 } 210 } 211 212 /* check timestamp */ 213 if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { 214 krb5_timestamp sec; 215 216 krb5_timeofday (context, &sec); 217 218 if (enc_krb_cred_part.timestamp == NULL || 219 enc_krb_cred_part.usec == NULL || 220 krb5_time_abs(*enc_krb_cred_part.timestamp, sec) 221 > context->max_skew) { 222 krb5_clear_error_message (context); 223 ret = KRB5KRB_AP_ERR_SKEW; 224 goto out; 225 } 226 } 227 228 if ((auth_context->flags & 229 (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) { 230 /* if these fields are not present in the cred-part, silently 231 return zero */ 232 memset(outdata, 0, sizeof(*outdata)); 233 if(enc_krb_cred_part.timestamp) 234 outdata->timestamp = *enc_krb_cred_part.timestamp; 235 if(enc_krb_cred_part.usec) 236 outdata->usec = *enc_krb_cred_part.usec; 237 if(enc_krb_cred_part.nonce) 238 outdata->seq = *enc_krb_cred_part.nonce; 239 } 240 241 /* Convert to NULL terminated list of creds */ 242 243 *ret_creds = calloc(enc_krb_cred_part.ticket_info.len + 1, 244 sizeof(**ret_creds)); 245 246 if (*ret_creds == NULL) { 247 ret = ENOMEM; 248 krb5_set_error_message(context, ret, 249 N_("malloc: out of memory", "")); 250 goto out; 251 } 252 253 for (i = 0; i < enc_krb_cred_part.ticket_info.len; ++i) { 254 KrbCredInfo *kci = &enc_krb_cred_part.ticket_info.val[i]; 255 krb5_creds *creds; 256 257 creds = calloc(1, sizeof(*creds)); 258 if(creds == NULL) { 259 ret = ENOMEM; 260 krb5_set_error_message(context, ret, 261 N_("malloc: out of memory", "")); 262 goto out; 263 } 264 265 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, 266 &cred.tickets.val[i], &len, ret); 267 if (ret) { 268 free(creds); 269 goto out; 270 } 271 if(creds->ticket.length != len) 272 krb5_abortx(context, "internal error in ASN.1 encoder"); 273 copy_EncryptionKey (&kci->key, &creds->session); 274 if (kci->prealm && kci->pname) 275 _krb5_principalname2krb5_principal (context, 276 &creds->client, 277 *kci->pname, 278 *kci->prealm); 279 if (kci->flags) 280 creds->flags.b = *kci->flags; 281 if (kci->authtime) 282 creds->times.authtime = *kci->authtime; 283 if (kci->starttime) 284 creds->times.starttime = *kci->starttime; 285 if (kci->endtime) 286 creds->times.endtime = *kci->endtime; 287 if (kci->renew_till) 288 creds->times.renew_till = *kci->renew_till; 289 if (kci->srealm && kci->sname) 290 _krb5_principalname2krb5_principal (context, 291 &creds->server, 292 *kci->sname, 293 *kci->srealm); 294 if (kci->caddr) 295 krb5_copy_addresses (context, 296 kci->caddr, 297 &creds->addresses); 298 299 (*ret_creds)[i] = creds; 300 301 } 302 (*ret_creds)[i] = NULL; 303 304 free_KRB_CRED (&cred); 305 free_EncKrbCredPart(&enc_krb_cred_part); 306 307 return 0; 308 309 out: 310 free_EncKrbCredPart(&enc_krb_cred_part); 311 free_KRB_CRED (&cred); 312 if(*ret_creds) { 313 for(i = 0; (*ret_creds)[i]; i++) 314 krb5_free_creds(context, (*ret_creds)[i]); 315 free(*ret_creds); 316 *ret_creds = NULL; 317 } 318 return ret; 319} 320 321KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 322krb5_rd_cred2 (krb5_context context, 323 krb5_auth_context auth_context, 324 krb5_ccache ccache, 325 krb5_data *in_data) 326{ 327 krb5_error_code ret; 328 krb5_creds **creds; 329 int i; 330 331 ret = krb5_rd_cred(context, auth_context, in_data, &creds, NULL); 332 if(ret) 333 return ret; 334 335 /* Store the creds in the ccache */ 336 337 for(i = 0; creds && creds[i]; i++) { 338 krb5_cc_store_cred(context, ccache, creds[i]); 339 krb5_free_creds(context, creds[i]); 340 } 341 free(creds); 342 return 0; 343} 344