1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray * may be used to endorse or promote products derived from this software
19b528cefcSMark Murray * without specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray * SUCH DAMAGE.
32b528cefcSMark Murray */
33b528cefcSMark Murray
34*ae771770SStanislav Sedov #include "krb5_locl.h"
35b528cefcSMark Murray
36c19800e8SDoug Rabson static krb5_error_code
compare_addrs(krb5_context context,krb5_address * a,krb5_address * b,const char * message)37c19800e8SDoug Rabson compare_addrs(krb5_context context,
38c19800e8SDoug Rabson krb5_address *a,
39c19800e8SDoug Rabson krb5_address *b,
40c19800e8SDoug Rabson const char *message)
41c19800e8SDoug Rabson {
42c19800e8SDoug Rabson char a_str[64], b_str[64];
43c19800e8SDoug Rabson size_t len;
44c19800e8SDoug Rabson
45c19800e8SDoug Rabson if(krb5_address_compare (context, a, b))
46c19800e8SDoug Rabson return 0;
47c19800e8SDoug Rabson
48c19800e8SDoug Rabson krb5_print_address (a, a_str, sizeof(a_str), &len);
49c19800e8SDoug Rabson krb5_print_address (b, b_str, sizeof(b_str), &len);
50*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5KRB_AP_ERR_BADADDR,
51*ae771770SStanislav Sedov "%s: %s != %s", message, b_str, a_str);
52c19800e8SDoug Rabson return KRB5KRB_AP_ERR_BADADDR;
53c19800e8SDoug Rabson }
54c19800e8SDoug Rabson
55*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_cred(krb5_context context,krb5_auth_context auth_context,krb5_data * in_data,krb5_creds *** ret_creds,krb5_replay_data * outdata)56b528cefcSMark Murray krb5_rd_cred(krb5_context context,
57b528cefcSMark Murray krb5_auth_context auth_context,
585e9cd1aeSAssar Westerlund krb5_data *in_data,
595e9cd1aeSAssar Westerlund krb5_creds ***ret_creds,
60c19800e8SDoug Rabson krb5_replay_data *outdata)
61b528cefcSMark Murray {
62b528cefcSMark Murray krb5_error_code ret;
63b528cefcSMark Murray size_t len;
64b528cefcSMark Murray KRB_CRED cred;
65b528cefcSMark Murray EncKrbCredPart enc_krb_cred_part;
66b528cefcSMark Murray krb5_data enc_krb_cred_part_data;
67b528cefcSMark Murray krb5_crypto crypto;
68*ae771770SStanislav Sedov size_t i;
69b528cefcSMark Murray
70c19800e8SDoug Rabson memset(&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part));
71*ae771770SStanislav Sedov krb5_data_zero(&enc_krb_cred_part_data);
72c19800e8SDoug Rabson
73c19800e8SDoug Rabson if ((auth_context->flags &
74c19800e8SDoug Rabson (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
75c19800e8SDoug Rabson outdata == NULL)
76c19800e8SDoug Rabson return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */
77c19800e8SDoug Rabson
78adb0ddaeSAssar Westerlund *ret_creds = NULL;
79adb0ddaeSAssar Westerlund
80b528cefcSMark Murray ret = decode_KRB_CRED(in_data->data, in_data->length,
81b528cefcSMark Murray &cred, &len);
82c19800e8SDoug Rabson if(ret) {
83*ae771770SStanislav Sedov krb5_clear_error_message(context);
84b528cefcSMark Murray return ret;
85c19800e8SDoug Rabson }
86b528cefcSMark Murray
87b528cefcSMark Murray if (cred.pvno != 5) {
88b528cefcSMark Murray ret = KRB5KRB_AP_ERR_BADVERSION;
89*ae771770SStanislav Sedov krb5_clear_error_message (context);
90b528cefcSMark Murray goto out;
91b528cefcSMark Murray }
92b528cefcSMark Murray
93b528cefcSMark Murray if (cred.msg_type != krb_cred) {
94b528cefcSMark Murray ret = KRB5KRB_AP_ERR_MSG_TYPE;
95*ae771770SStanislav Sedov krb5_clear_error_message (context);
96b528cefcSMark Murray goto out;
97b528cefcSMark Murray }
98b528cefcSMark Murray
995e9cd1aeSAssar Westerlund if (cred.enc_part.etype == ETYPE_NULL) {
1005e9cd1aeSAssar Westerlund /* DK: MIT GSS-API Compatibility */
1015e9cd1aeSAssar Westerlund enc_krb_cred_part_data.length = cred.enc_part.cipher.length;
1025e9cd1aeSAssar Westerlund enc_krb_cred_part_data.data = cred.enc_part.cipher.data;
1035e9cd1aeSAssar Westerlund } else {
104c19800e8SDoug Rabson /* Try both subkey and session key.
105c19800e8SDoug Rabson *
106c19800e8SDoug Rabson * RFC4120 claims we should use the session key, but Heimdal
107c19800e8SDoug Rabson * before 0.8 used the remote subkey if it was send in the
108c19800e8SDoug Rabson * auth_context.
109c19800e8SDoug Rabson */
110c19800e8SDoug Rabson
111c19800e8SDoug Rabson if (auth_context->remote_subkey) {
1125e9cd1aeSAssar Westerlund ret = krb5_crypto_init(context, auth_context->remote_subkey,
1135e9cd1aeSAssar Westerlund 0, &crypto);
114c19800e8SDoug Rabson if (ret)
115c19800e8SDoug Rabson goto out;
116c19800e8SDoug Rabson
117c19800e8SDoug Rabson ret = krb5_decrypt_EncryptedData(context,
118c19800e8SDoug Rabson crypto,
119c19800e8SDoug Rabson KRB5_KU_KRB_CRED,
120c19800e8SDoug Rabson &cred.enc_part,
121c19800e8SDoug Rabson &enc_krb_cred_part_data);
122c19800e8SDoug Rabson
123c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto);
124c19800e8SDoug Rabson }
125c19800e8SDoug Rabson
126c19800e8SDoug Rabson /*
127c19800e8SDoug Rabson * If there was not subkey, or we failed using subkey,
128c19800e8SDoug Rabson * retry using the session key
129c19800e8SDoug Rabson */
130c19800e8SDoug Rabson if (auth_context->remote_subkey == NULL || ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
131c19800e8SDoug Rabson {
132c19800e8SDoug Rabson
1335e9cd1aeSAssar Westerlund ret = krb5_crypto_init(context, auth_context->keyblock,
1345e9cd1aeSAssar Westerlund 0, &crypto);
1355e9cd1aeSAssar Westerlund
1365e9cd1aeSAssar Westerlund if (ret)
1375e9cd1aeSAssar Westerlund goto out;
1385e9cd1aeSAssar Westerlund
139b528cefcSMark Murray ret = krb5_decrypt_EncryptedData(context,
140b528cefcSMark Murray crypto,
141b528cefcSMark Murray KRB5_KU_KRB_CRED,
142b528cefcSMark Murray &cred.enc_part,
143b528cefcSMark Murray &enc_krb_cred_part_data);
1445e9cd1aeSAssar Westerlund
145b528cefcSMark Murray krb5_crypto_destroy(context, crypto);
146c19800e8SDoug Rabson }
147b528cefcSMark Murray if (ret)
148b528cefcSMark Murray goto out;
1495e9cd1aeSAssar Westerlund }
150b528cefcSMark Murray
151*ae771770SStanislav Sedov ret = decode_EncKrbCredPart(enc_krb_cred_part_data.data,
152b528cefcSMark Murray enc_krb_cred_part_data.length,
153b528cefcSMark Murray &enc_krb_cred_part,
154b528cefcSMark Murray &len);
155c19800e8SDoug Rabson if (enc_krb_cred_part_data.data != cred.enc_part.cipher.data)
156c19800e8SDoug Rabson krb5_data_free(&enc_krb_cred_part_data);
157*ae771770SStanislav Sedov if (ret) {
158*ae771770SStanislav Sedov krb5_set_error_message(context, ret,
159*ae771770SStanislav Sedov N_("Failed to decode "
160*ae771770SStanislav Sedov "encrypte credential part", ""));
161b528cefcSMark Murray goto out;
162*ae771770SStanislav Sedov }
163b528cefcSMark Murray
164b528cefcSMark Murray /* check sender address */
165b528cefcSMark Murray
166b528cefcSMark Murray if (enc_krb_cred_part.s_address
1675e9cd1aeSAssar Westerlund && auth_context->remote_address
1685e9cd1aeSAssar Westerlund && auth_context->remote_port) {
169b528cefcSMark Murray krb5_address *a;
170b528cefcSMark Murray
171adb0ddaeSAssar Westerlund ret = krb5_make_addrport (context, &a,
172b528cefcSMark Murray auth_context->remote_address,
173b528cefcSMark Murray auth_context->remote_port);
174b528cefcSMark Murray if (ret)
175b528cefcSMark Murray goto out;
176b528cefcSMark Murray
177b528cefcSMark Murray
178c19800e8SDoug Rabson ret = compare_addrs(context, a, enc_krb_cred_part.s_address,
179*ae771770SStanislav Sedov N_("sender address is wrong "
180*ae771770SStanislav Sedov "in received creds", ""));
181b528cefcSMark Murray krb5_free_address(context, a);
182b528cefcSMark Murray free(a);
183c19800e8SDoug Rabson if(ret)
184b528cefcSMark Murray goto out;
185b528cefcSMark Murray }
186b528cefcSMark Murray
187b528cefcSMark Murray /* check receiver address */
188b528cefcSMark Murray
189b528cefcSMark Murray if (enc_krb_cred_part.r_address
1908373020dSJacques Vidrine && auth_context->local_address) {
1918373020dSJacques Vidrine if(auth_context->local_port &&
1928373020dSJacques Vidrine enc_krb_cred_part.r_address->addr_type == KRB5_ADDRESS_ADDRPORT) {
1938373020dSJacques Vidrine krb5_address *a;
1948373020dSJacques Vidrine ret = krb5_make_addrport (context, &a,
1958373020dSJacques Vidrine auth_context->local_address,
1968373020dSJacques Vidrine auth_context->local_port);
1978373020dSJacques Vidrine if (ret)
1988373020dSJacques Vidrine goto out;
1998373020dSJacques Vidrine
200c19800e8SDoug Rabson ret = compare_addrs(context, a, enc_krb_cred_part.r_address,
201*ae771770SStanislav Sedov N_("receiver address is wrong "
202*ae771770SStanislav Sedov "in received creds", ""));
2038373020dSJacques Vidrine krb5_free_address(context, a);
2048373020dSJacques Vidrine free(a);
205c19800e8SDoug Rabson if(ret)
2068373020dSJacques Vidrine goto out;
2078373020dSJacques Vidrine } else {
208c19800e8SDoug Rabson ret = compare_addrs(context, auth_context->local_address,
209c19800e8SDoug Rabson enc_krb_cred_part.r_address,
210*ae771770SStanislav Sedov N_("receiver address is wrong "
211*ae771770SStanislav Sedov "in received creds", ""));
212c19800e8SDoug Rabson if(ret)
213b528cefcSMark Murray goto out;
214b528cefcSMark Murray }
2158373020dSJacques Vidrine }
216b528cefcSMark Murray
217b528cefcSMark Murray /* check timestamp */
218b528cefcSMark Murray if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
21913e3f4d6SMark Murray krb5_timestamp sec;
220b528cefcSMark Murray
221b528cefcSMark Murray krb5_timeofday (context, &sec);
222b528cefcSMark Murray
223b528cefcSMark Murray if (enc_krb_cred_part.timestamp == NULL ||
224b528cefcSMark Murray enc_krb_cred_part.usec == NULL ||
225b528cefcSMark Murray abs(*enc_krb_cred_part.timestamp - sec)
226b528cefcSMark Murray > context->max_skew) {
227*ae771770SStanislav Sedov krb5_clear_error_message (context);
228b528cefcSMark Murray ret = KRB5KRB_AP_ERR_SKEW;
229b528cefcSMark Murray goto out;
230b528cefcSMark Murray }
231b528cefcSMark Murray }
232b528cefcSMark Murray
233c19800e8SDoug Rabson if ((auth_context->flags &
234c19800e8SDoug Rabson (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) {
235c19800e8SDoug Rabson /* if these fields are not present in the cred-part, silently
236c19800e8SDoug Rabson return zero */
237c19800e8SDoug Rabson memset(outdata, 0, sizeof(*outdata));
2385e9cd1aeSAssar Westerlund if(enc_krb_cred_part.timestamp)
239c19800e8SDoug Rabson outdata->timestamp = *enc_krb_cred_part.timestamp;
2405e9cd1aeSAssar Westerlund if(enc_krb_cred_part.usec)
241c19800e8SDoug Rabson outdata->usec = *enc_krb_cred_part.usec;
2425e9cd1aeSAssar Westerlund if(enc_krb_cred_part.nonce)
243c19800e8SDoug Rabson outdata->seq = *enc_krb_cred_part.nonce;
2445e9cd1aeSAssar Westerlund }
245b528cefcSMark Murray
2465e9cd1aeSAssar Westerlund /* Convert to NULL terminated list of creds */
2475e9cd1aeSAssar Westerlund
2485e9cd1aeSAssar Westerlund *ret_creds = calloc(enc_krb_cred_part.ticket_info.len + 1,
2495e9cd1aeSAssar Westerlund sizeof(**ret_creds));
250b528cefcSMark Murray
2514137ff4cSJacques Vidrine if (*ret_creds == NULL) {
2524137ff4cSJacques Vidrine ret = ENOMEM;
253*ae771770SStanislav Sedov krb5_set_error_message(context, ret,
254*ae771770SStanislav Sedov N_("malloc: out of memory", ""));
2554137ff4cSJacques Vidrine goto out;
2564137ff4cSJacques Vidrine }
2574137ff4cSJacques Vidrine
258b528cefcSMark Murray for (i = 0; i < enc_krb_cred_part.ticket_info.len; ++i) {
259b528cefcSMark Murray KrbCredInfo *kci = &enc_krb_cred_part.ticket_info.val[i];
2605e9cd1aeSAssar Westerlund krb5_creds *creds;
261b528cefcSMark Murray
2625e9cd1aeSAssar Westerlund creds = calloc(1, sizeof(*creds));
2635e9cd1aeSAssar Westerlund if(creds == NULL) {
2645e9cd1aeSAssar Westerlund ret = ENOMEM;
265*ae771770SStanislav Sedov krb5_set_error_message(context, ret,
266*ae771770SStanislav Sedov N_("malloc: out of memory", ""));
2675e9cd1aeSAssar Westerlund goto out;
2685e9cd1aeSAssar Westerlund }
269b528cefcSMark Murray
2700cadf2f4SJacques Vidrine ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
2710cadf2f4SJacques Vidrine &cred.tickets.val[i], &len, ret);
272c19800e8SDoug Rabson if (ret) {
273c19800e8SDoug Rabson free(creds);
274b528cefcSMark Murray goto out;
275c19800e8SDoug Rabson }
2760cadf2f4SJacques Vidrine if(creds->ticket.length != len)
2770cadf2f4SJacques Vidrine krb5_abortx(context, "internal error in ASN.1 encoder");
2785e9cd1aeSAssar Westerlund copy_EncryptionKey (&kci->key, &creds->session);
279b528cefcSMark Murray if (kci->prealm && kci->pname)
280c19800e8SDoug Rabson _krb5_principalname2krb5_principal (context,
281c19800e8SDoug Rabson &creds->client,
282b528cefcSMark Murray *kci->pname,
283b528cefcSMark Murray *kci->prealm);
284b528cefcSMark Murray if (kci->flags)
2855e9cd1aeSAssar Westerlund creds->flags.b = *kci->flags;
286b528cefcSMark Murray if (kci->authtime)
2875e9cd1aeSAssar Westerlund creds->times.authtime = *kci->authtime;
288b528cefcSMark Murray if (kci->starttime)
2895e9cd1aeSAssar Westerlund creds->times.starttime = *kci->starttime;
290b528cefcSMark Murray if (kci->endtime)
2915e9cd1aeSAssar Westerlund creds->times.endtime = *kci->endtime;
292b528cefcSMark Murray if (kci->renew_till)
2935e9cd1aeSAssar Westerlund creds->times.renew_till = *kci->renew_till;
294b528cefcSMark Murray if (kci->srealm && kci->sname)
295c19800e8SDoug Rabson _krb5_principalname2krb5_principal (context,
296c19800e8SDoug Rabson &creds->server,
297b528cefcSMark Murray *kci->sname,
298b528cefcSMark Murray *kci->srealm);
299b528cefcSMark Murray if (kci->caddr)
300b528cefcSMark Murray krb5_copy_addresses (context,
301b528cefcSMark Murray kci->caddr,
3025e9cd1aeSAssar Westerlund &creds->addresses);
3035e9cd1aeSAssar Westerlund
3045e9cd1aeSAssar Westerlund (*ret_creds)[i] = creds;
3055e9cd1aeSAssar Westerlund
306b528cefcSMark Murray }
3075e9cd1aeSAssar Westerlund (*ret_creds)[i] = NULL;
308c19800e8SDoug Rabson
309c19800e8SDoug Rabson free_KRB_CRED (&cred);
310c19800e8SDoug Rabson free_EncKrbCredPart(&enc_krb_cred_part);
311c19800e8SDoug Rabson
3125e9cd1aeSAssar Westerlund return 0;
313b528cefcSMark Murray
314b528cefcSMark Murray out:
315c19800e8SDoug Rabson free_EncKrbCredPart(&enc_krb_cred_part);
316b528cefcSMark Murray free_KRB_CRED (&cred);
3175e9cd1aeSAssar Westerlund if(*ret_creds) {
3185e9cd1aeSAssar Westerlund for(i = 0; (*ret_creds)[i]; i++)
3195e9cd1aeSAssar Westerlund krb5_free_creds(context, (*ret_creds)[i]);
3205e9cd1aeSAssar Westerlund free(*ret_creds);
321c19800e8SDoug Rabson *ret_creds = NULL;
3225e9cd1aeSAssar Westerlund }
323b528cefcSMark Murray return ret;
324b528cefcSMark Murray }
3255e9cd1aeSAssar Westerlund
326*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_cred2(krb5_context context,krb5_auth_context auth_context,krb5_ccache ccache,krb5_data * in_data)3275e9cd1aeSAssar Westerlund krb5_rd_cred2 (krb5_context context,
3285e9cd1aeSAssar Westerlund krb5_auth_context auth_context,
3295e9cd1aeSAssar Westerlund krb5_ccache ccache,
3305e9cd1aeSAssar Westerlund krb5_data *in_data)
3315e9cd1aeSAssar Westerlund {
3325e9cd1aeSAssar Westerlund krb5_error_code ret;
3335e9cd1aeSAssar Westerlund krb5_creds **creds;
3345e9cd1aeSAssar Westerlund int i;
3355e9cd1aeSAssar Westerlund
3365e9cd1aeSAssar Westerlund ret = krb5_rd_cred(context, auth_context, in_data, &creds, NULL);
3375e9cd1aeSAssar Westerlund if(ret)
3385e9cd1aeSAssar Westerlund return ret;
3395e9cd1aeSAssar Westerlund
3405e9cd1aeSAssar Westerlund /* Store the creds in the ccache */
3415e9cd1aeSAssar Westerlund
3425e9cd1aeSAssar Westerlund for(i = 0; creds && creds[i]; i++) {
3435e9cd1aeSAssar Westerlund krb5_cc_store_cred(context, ccache, creds[i]);
3445e9cd1aeSAssar Westerlund krb5_free_creds(context, creds[i]);
3455e9cd1aeSAssar Westerlund }
3465e9cd1aeSAssar Westerlund free(creds);
3475e9cd1aeSAssar Westerlund return 0;
3485e9cd1aeSAssar Westerlund }
349